Как сообщить линкеру MinGW не экспортировать все символы?
Я создаю динамическую библиотеку Windows с помощью инструментальной комбинации MinGW.
Чтобы создать эту библиотеку, я статически связываюсь с другими 2, предлагающими API, и у меня есть файл .def
, где я написал единственный символ, который я хочу экспортировать в своей библиотеке.
Проблема заключается в том, что GCC экспортирует все символы, включая те из библиотек, к которым я привязываюсь. В любом случае, чтобы сообщить компоновщику просто экспортировать символы в файл def
?
Я знаю, что есть опция --export-all-symbols
, но, похоже, это не так.
В настоящее время последняя строка сборки script имеет следующую структуру:
g++ -shared CXXFLAGS DEFINES INCLUDES -o library.dll library.cpp DEF_FILE \
OBJECT_FILES LIBS -Wl,--enable-stdcall-fixup
EDIT: В docs о компоновщике говорится, что --export-all-symbols
является поведением по умолчанию и что он отключен, когда вы не используете эту опцию явно, если вы предоставляете файл def
, за исключением случаев, когда это не так; в любом случае экспортируются символы в сторонних библиотеках.
EDIT: добавление опции --exclude-libs LIBS
или –exclude-symbols SYMBOLS
не позволяет экспортировать символы из библиотек.
Ответы
Ответ 1
Вы можете использовать dllwrap, если это дает вам дистрибутив binutils (как встроенного, так и кросс-компиляции).
Он может создавать библиотеки DLL, используя интерфейс в DEF файле (под капотом он вызывает gcc, ld и dlltool для этого). Разница между использованием этого и передачей DEF файла в GCC напрямую заключается в том, что определения в файле обрабатываются по-разному.
Например, если у вас есть символ переименования в файле экспорта:
_SomeFuntion = [email protected]
GCC создаст 2 экспорта, один по имени _SomeFunction
, а другой - с украшенным именем, а dllwrap будет экспортировать только _SomeFuntion
. Поэтому, если вы только добавите в файл DEF символы, которые хотите экспортировать, вы попадете только в них в библиотеке.
dllwrap по умолчанию использует драйвер компилятора C, поскольку он не знает иначе. Когда вы связываете код С++, вы должны использовать опцию --driver-name c++
для установки драйвера. Если у вас есть исполняемые файлы MinGW с префиксом, вы должны включить его также в имя драйвера (например, i686-mingw32-c++
вместо c++
), и вам может понадобиться также использовать параметр --dlltool-name
.
Попробуйте использовать эти две строки вместо той, которую вы разместили:
g++ -c CXXFLAGS DEFINES INCLUDES -o library.o library.cpp
dllwrap -o library.dll --driver-name c++ --def DEF_FILE OBJECT_FILES LIBS -Wl,--enable-stdcall-fixup
Первый генерирует объектный файл из кода library.cpp
, а второй собирает динамическую библиотеку. Объект OBJECT_FILES
(который, как я полагаю, является другим объектным файлом, созданным ранее), должен иметь library.o
.
Тем не менее, я должен сказать, что dllwrap уже был устарел в 2006 году, и в официальном пакете binutils нет документации; для получения информации вы можете назвать ее с помощью --help
, как обычно. Он может генерировать библиотеку импорта, если она вам тоже нужна.
Ответ 2
Не знаю, почему на это нет реального ответа, но вот что для меня работало:
-
Компиляция ваших объектных файлов:
g++ -O0 -gdwarf-4 dll\dllmain.cpp -c -o dllmain.o
-
Связывание (-Wl,--exclude-all-symbols
важно):
g++ -Wl,--enable-auto-import -Wl,--out-implib,libsomelib.a -Wl,--exclude-all-symbols -shared dllmain.o -o somelib.dll
Затем вы выбираете, какие функции экспортировать непосредственно в исходный код вашей DLL:
#include <windows.h>
__declspec(dllexport) void someExportedFunction() {
MessageBox(NULL, "msgbox", "msgbox", MB_OK);
}
void nonExportedFunction() {
MessageBox(NULL, "notexported", "notexported", MB_OK);
}
Проверка:
C:\libtest>pedump -E somelib.dll
=== EXPORTS ===
# module "somelib.dll"
# flags=0x0 ts="2014-02-20 08:37:48" version=0.0 ord_base=1
# nFuncs=1 nNames=1
ORD ENTRY_VA NAME
1 1570 _Z20someExportedFunctionv
(pedump
= http://pedump.me)
Ответ 3
Это повторяющаяся проблема. Вот два связанных вопроса в SO:
и вне SO:
то есть. глобальный/локальный экспорт на платформе Windows не обрабатывается на уровне компоновщика, а предоставляется файл .def
для дополнения .dll
.
Отсутствие хорошего ответа, я сделал python script, который заботится о удалении файлов из таблицы экспорта dll, вы можете найти его здесь.
Ответ 4
Вы прочитали это на странице, на которую вы предоставили ссылку, относительно поведения, если --export-all-symbols не используется явно - автоматический экспорт отключен, если:
Любой символ в любом объектном файле отмечен __declspec (dllexport) атрибут.
Вы пытались явно экспортировать только те функции, которые вас интересуют? Очень легко получить неправильные имена в DEF файле, из-за mangling, поэтому этот метод должен быть более надежным.
Ответ 5
Вы можете использовать опцию -Wl,--retain-symbols-file=file
, а затем перечислить символы, которые вы хотите сохранить (по одной в строке), в file
. Это заставит компоновщик сбросить все остальные символы, сохранив только те, которые вы хотите.
Ответ 6
Отказ от ответственности: я сделал это только в Linux, но AFAIK также должен работать на Windows
Вы можете использовать опцию -fvisibility=hidden
; для получения дополнительной информации см. http://gcc.gnu.org/wiki/Visibility