Экспорт всех символов при создании библиотеки DLL



с VS2005 я хочу создать DLL и автоматически экспортировать все символы без добавления _ _ declspec (dllexport) везде и без ручного создания .Def-файлов. Есть ли способ сделать это?

785   5  

5 ответов:

Это можно сделать...

Как мы это делаем здесь, чтобы использовать параметр / DEF компоновщика для передачи файл"определение модуля" содержащий список нашего экспорта. Я вижу из вашего вопроса, Что вы знаете об этих файлах. Однако, мы не делаем это вручную. Сам список экспорта создается с помощью команду dumpbin /LINKERMEMBER команда, и манипулирование выводом с помощью простого скрипта в формат файла определения модуля.

Это много работа по настройке, но это позволяет нам компилировать код, созданный без объявления dllexport для Unix на Windows.

короткий ответ:

вы можете сделать это с помощью новой версии CMake (любая версия cmake-3.3.20150721-g9cd2f-win32-x86.ехе или выше).

в настоящее время он находится в ветви dev. Позже эта функция будет добавлена в релизную версию cmake-3.4.

ссылка на cmake dev:

cmake_dev

ссылка на статью, которая описывает технику:

создание DLL в Windows без declspec () с помощью нового CMake экспортировать все функции

ссылка на пример проекта:

cmake_windows_export_all_symbols


ответ

внимание: Вся приведенная ниже информация относится к компилятору MSVC или Visual Studio.

если вы используете другие компиляторы, такие как gcc в Linux или MinGW GCC compiler в Windows, у вас нет ошибок связывания из - за не экспортированных символов, поскольку компилятор gcc экспортирует все символы в динамическую библиотеку (dll) по умолчанию вместо компиляторов MSVC или Intel windows.

в windows вы должны явно экспортировать символ из dll.

более подробная информация об этом предоставляется по ссылкам:

экспорт из DLL

HowTo: экспорт классов C++ из DLL

поэтому, если вы хотите экспортировать все символы из dll с помощью MSVC (компилятор Visual Studio) у вас есть два варианта:

  • используйте ключевое слово _ _ declspec (dllexport) в определении класса/функции.
  • создать определение модуля (.def) файл и использовать .def-файл при создании библиотеки DLL.

1. Используйте ключевое слово _ _ declspec (dllexport) в определении класса/функции


1.1. Добавить "ключевое слово__declspec(dllexport) или / ключевое слово __declspec(DllImport) и" макросы для класса или метода, который вы хотите использовать. Поэтому, если вы хотите экспортировать все классы, вы должны добавить эти макросы ко всем из них

более подробная информация об этом предоставлена по ссылке:

экспорт из DLL с помощью _ _ declspec (dllexport)

пример использования (заменить "проект" на реальное имя проекта):

// ProjectExport.h

#ifndef __PROJECT_EXPORT_H
#define __PROJECT_EXPORT_H

#ifdef USEPROJECTLIBRARY
#ifdef  PROJECTLIBRARY_EXPORTS 
#define PROJECTAPI __declspec(dllexport)
#else
#define PROJECTAPI __declspec(dllimport)
#endif
#else
#define PROJECTAPI
#endif

#endif

затем добавьте "PROJECTAPI" для всех классов. Определите "USEPROJECTLIBRARY" только если вы хотите экспортировать/импортировать символы из dll. Определите "PROJECTLIBRARY_EXPORTS" для файл DLL.

пример экспорта класса:

#include "ProjectExport.h"

namespace hello {
    class PROJECTAPI Hello {}   
}

пример экспорта функции:

#include "ProjectExport.h"

PROJECTAPI void HelloWorld();

внимание: не забудьте включить " ProjectExport.H-файл".


1.2. Как экспортировать функции C. Если вы используете компилятор C++ для компиляции кода, написанного на C, вы можете добавить extern " C " перед функцией, чтобы устранить искажение имени

дополнительная информация о c++ name mangling предоставляется ссылка:

Название Украшения

пример использования:

extern "C" __declspec(dllexport) void HelloWorld();

более подробная информация об этом предоставлена по ссылке:

экспорт функций C++ для использования в исполняемых файлах C-языка


2. Создайте определение модуля (.def) файл и использовать .def файл при построении DLL

более подробная информация об этом предоставлена по ссылке:

экспорт из DLL с помощью DEF-файлов

далее я опишу три подхода о том, как создать .def file.


2.1. Экспорт функций C

в этом случае вы можете просто добавить объявления функций в поле .def файл вручную.

пример использования:

extern "C" void HelloWorld();

пример .def-файл (__cdecl соглашение об именовании):

EXPORTS 
_HelloWorld

2.2. Экспортировать символы из статического библиотека

я попробовал подход, предложенный "user72260".

он сказал:

  • во-первых, вы можете создать статическую библиотеку.
  • затем используйте "dumpbin /LINKERMEMBER" для экспорта всех символов из статической библиотеки.
  • разбор вывода.
  • Поместите все результаты в a .def file.
  • создать dll с помощью .def file.

я использовал этот подход, но это не очень удобно всегда создайте две сборки (одну как статическую, а другую как динамическую библиотеку). Однако, должен признать, такой подход действительно работает.


2.3. Экспорт символов из .obj файлы или с помощью CMake


2.3.1. С использованием CMake, например,

важное замечание: вам не нужны никакие макросы экспорта к классам или функциям!

важное замечание: вы не можете использовать /GL (Оптимизация Всей Программы) при использовании этого подхода!

  • создать проект CMake на основе " CMakeLists.txt-файл.
  • добавить следующую строку в "CMakeLists.txt-файл: set (CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
  • затем создайте проект Visual Studio с помощью " CMake (cmake-gui)".
  • скомпилировать проект.

пример использования:

корень папка

CMakeLists.txt (корневая папка)

cmake_minimum_required(VERSION 2.6)
project(cmake_export_all)

set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

set(dir ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${dir}/bin")

set(SOURCE_EXE main.cpp)

include_directories(foo)

add_executable(main ${SOURCE_EXE})

add_subdirectory(foo)

target_link_libraries(main foo)

главная.СРР (корневая папка)

#include "foo.h"

int main() {
    HelloWorld();

    return 0;
}

папку Foo (корневая папка с именем / foo)

CMakeLists.txt (Foo folder)

project(foo)

set(SOURCE_LIB foo.cpp)

add_library(foo SHARED ${SOURCE_LIB})

фу.h (Foo folder)

void HelloWorld();

фу.cpp (Foo folder)

#include <iostream>

void HelloWorld() {
    std::cout << "Hello World!" << std::endl;
}

ссылка на пример проекта и снова:

cmake_windows_export_all_symbols

CMake использует отличается от " 2.2. Экспорт символов из статической библиотеки " подход.

он делает следующее:

1) Создание "объектов.txt " файл в каталоге сборки с информацией о компании .obj файлы используются в dll.

2) скомпилировать dll, то есть создать .obj-файлы.

3) на основе "объектов.txt " информация о файле извлечение всех символов из .файл obj.

пример использования:

DUMPBIN /SYMBOLS example.obj > log.txt

более подробная информация об этом предоставлена по ссылке:

/символы

4) разбор извлечен из .в obj файле.

на мой взгляд, я бы использовал вызов конвекции, например "_ _ cdecl / __fastcall", "SECTx/UNDEF" поле символов (третий столбец), "внешнее/статическое" поле символов (пятый столбец),"??","?"информация для разбора Ан .параметр obj файлы.

я не знаю, как именно CMake разобрать .файл obj. Тем не менее, CMake является открытым исходным кодом, так что вы можете узнать, если это интересно для вас.

ссылка на проект CMake:

CMake_github

5) Поместите все экспортированные символы в a .def file.

6) свяжите dll с использованием a .def создал файл.

шаги 4)-5), то есть разобрать .obj-файлы и создания .def-файл перед связыванием и использованием .def файл CMake делает с помощью "Pre-Link event". В то время как" Pre-Link event " срабатывает, вы можете вызвать любую программу, которую хотите. Поэтому в случае "использования CMake" "Pre-Link event" вызовите CMake со следующей информацией о том, где поставить .Def файл и где "объекты.txt "файл и с аргументом" - E __create_def". Вы можете проверить эту информацию, создав проект CMake Visusal Studio с "set (CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)", а затем проверить ".vcxproj " файл проекта для файл DLL.

если вы попытаетесь скомпилировать проект без " set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)" или с "set (CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS OFF)", вы получите ошибки связывания из-за того, что символы не экспортируются из dll.

более подробная информация об этом предоставлена по ссылке:

понимание об этапах настраиваемого построения и событиях построения


2.3.2. Без использования CMake, например,

вы просто можно создать небольшую программу для парсинга .obj файл сам по себе без CMake usege. Hovewer, я должен признать, что CMake-очень полезная программа, особенно для кросс-платформенной разработки.

Я написал небольшую программу для разбора вывода "dumpbin / linkermember".файла lib. У меня есть более 8000 ссылок на функции для экспорта из одной DLL.

проблема с этим в DLL заключается в том, что вам нужно связать DLL без экспортированных определений один раз, чтобы создать .lib-файл, затем создать .def, что означает, что теперь вам нужно снова связать DLL с помощью .def-файл, чтобы фактически экспортировать ссылки.

работа со статикой библиотеки проще. Скомпилируйте все свои источники в статические библиотеки, запустите dumbin, сгенерируйте a .def с вашей маленькой программой, а затем связать библиотеки вместе в DLL теперь, когда имена экспорта доступны.

к сожалению, моя компания не позвольте мне показать вам источник. Работа заключается в распознавании того, какие "публичные символы" в выводе дампа не нужны в вашем файле def. Вы должны выбросить много этих ссылок, NULL_IMPORT_DESCRIPTOR, NULL_THUNK_DATA, __imp*, так далее.

спасибо @Maks за подробный ответ!--3-->.

Ниже приведен пример того, что я использовал в Pre-Link event для создания def-файла из obj. Я надеюсь, это будет полезно для кого-то.

dumpbin /SYMBOLS $(Platform)$(Configuration)\mdb.obj | findstr /R "().*External.*mdb_.*" > $(Platform)$(Configuration)\mdb_symbols
(echo EXPORTS & for /F "usebackq tokens=2 delims==|" %%E in (`type $(Platform)$(Configuration)\mdb_symbols`) do @echo  %%E) > $(Platform)$(Configuration)\lmdb.def

в основном я просто взял один из объектов (mdb.obj) и grepped mdb_* функции. Затем анализируется вывод, чтобы сохранить только имена с учетом количества пробелов для отступа (один после разбиения на токены и другой в echo. Я не знаю, если это имеет значение хотя.)

сценарий реального мира, вероятно,будет более сложным.

нет, вам понадобится макрос, который разрешает __declspec(dllexport) когда он включен .cpp-файл, который реализует экспортированные функции и разрешает __declspec(dllimport) в противном случае.

Comments

    Ничего не найдено.