Как сказать компоновщику MinGW не экспортировать все символы? - PullRequest
13 голосов
/ 11 мая 2010

Я создаю динамическую библиотеку Windows, используя набор инструментов MinGW.

Чтобы создать эту библиотеку, я статически связываюсь с двумя другими, которые предлагают API, и у меня есть файл .def, где я написал единственный символ, который я хочу экспортировать в мою библиотеку.

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

Я знаю, что есть опция --export-all-symbols, но, кажется, нет противоположности ей.

Прямо сейчас последняя строка скрипта сборки имеет такую ​​структуру:

g++ -shared CXXFLAGS DEFINES INCLUDES -o library.dll library.cpp DEF_FILE \
OBJECT_FILES LIBS -Wl,--enable-stdcall-fixup

РЕДАКТИРОВАТЬ: В документах о компоновщике говорится, что --export-all-symbols является поведением по умолчанию и отключено, если вы не используете эту опцию явно, если вы предоставляете файл def, кроме когда это не так; символы в сторонних библиотеках все равно экспортируются.

РЕДАКТИРОВАТЬ: Добавление опции --exclude-libs LIBS или –exclude-symbols SYMBOLS не препятствует экспорту символов из библиотек.

Ответы [ 6 ]

3 голосов
/ 20 февраля 2014

Не уверен, почему нет реального ответа на это, но вот что сработало для меня:

  1. Компиляция ваших объектных файлов:

    g++ -O0 -gdwarf-4 dll\dllmain.cpp -c -o dllmain.o
    
  2. Связывание (-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)

2 голосов
/ 07 марта 2012

Это повторяющаяся проблема. Вот два связанных вопроса в SO:

и вне SO:

т.е. Глобальный / локальный экспорт на платформе Windows не обрабатывается на уровне компоновщика, но предоставляется файл .def для дополнения .dll.

Не имея хорошего ответа, я написал скрипт на python, который позаботится об удалении содержимого из таблицы экспорта dll, вы можете найти его здесь .

1 голос
/ 21 декабря 2011

Вы можете использовать опцию -Wl,--retain-symbols-file=file и затем перечислить символы, которые вы хотите сохранить (по одному на строку) в file. Это заставит компоновщик отбросить все остальные символы, оставив только те, которые вы хотите.

1 голос
/ 11 мая 2010

Вы можете использовать dllwrap, если ваш дистрибутив binutils (как нативной, так и кросс-компиляции) обеспечивает это.

Он может создавать библиотеки DLL, используя интерфейс в файле DEF (для этого он вызывает gcc, ld и dlltool). Разница между использованием этого и передачей файла DEF непосредственно в GCC заключается в том, что определения в файле обрабатываются по-разному.

Например, если у вас есть символ переименования в файле экспорта:

_SomeFuntion = _SomeFunction@12

GCC создаст 2 экспорта, один с именем _SomeFunction, а другой с декорированным именем, в то время как dllwrap будет экспортировать только _SomeFuntion. Поэтому, если вы добавите в файл DEF только те символы, которые вы хотите экспортировать, то в итоге вы попадете только в библиотеку.

dllwrap по умолчанию использует драйвер компилятора C, так как он не может знать иначе. Когда вы связываете код 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 как обычно. Он может сгенерировать библиотеку импорта, если она вам тоже понадобится.

1 голос
/ 11 мая 2010

Читали ли вы это на странице, на которую вы указали, относительно поведения, если --export-all-символы явно не используются - автоматический экспорт отключен, если:

Любой символ в любом объектном файле был помечены __declspec (dllexport) приписывать.

Вы пытались явно экспортировать только те функции, которые вас интересуют? Из-за искажения очень легко ошибиться в именах файлов DEF, поэтому этот метод должен быть более надежным.

0 голосов
/ 11 мая 2010

Отказ от ответственности: я делал это только в Linux, но AFAIK это должно работать и в Windows

Вы можете использовать опцию -fvisibility=hidden; для получения дополнительной информации см http://gcc.gnu.org/wiki/Visibility

...