.def файлы C / C ++ DLLs

Я не понимаю смысла использования файлов .def с DLL.

Кажется, это заменяет необходимость использовать явный экспорт в вашем коде DLL (т.е. явный __declspec (dllexport)), однако я не могу сгенерировать файл lib, когда он не используется, что позже создает проблемы компоновщика при использовании DLL.

Итак, как вы используете .defs при связывании с клиентским приложением, заменяют ли они необходимость использовать заголовочный файл или файл .lib?

14.12.2008 06:31:52
6 ОТВЕТОВ
РЕШЕНИЕ

Насколько я понимаю, файлы .def предоставляют альтернативу синтаксису __declspec (dllexport), с дополнительным преимуществом возможности явно указывать порядковые номера экспортируемых функций. Это может быть полезно, если вы экспортируете некоторые функции только по порядковому номеру, который не раскрывает столько информации о самой функции (например, многие из функций экспорта внутренней DLL операционной системы только по порядковому номеру).

Смотрите справочную страницу .

Обратите внимание, что имена в файле .def должны совпадать с именами в двоичном файле. Поэтому, если вы используете C или C ++ с 'extern "C" {...}', имена не будут искажены; в противном случае вы должны использовать правильные искаженные имена для конкретной версии компилятора, используемой для генерации DLL. Функция __declspec () делает все это автоматически.

20
7.02.2020 06:01:02
Как сказал М. Клуни: «Что еще?». +1. Как разработчик Windows, мой опыт заключается в том, что файлы DEF являются «старым способом» и должны быть признаны устаревшими (если это еще не сделано).
paercebal 14.12.2008 15:20:22
Да, файлы .def предшествуют расширениям языка __declspec. В файле .def вы ничего не можете сделать, что нельзя сделать ни с __declspec, ни с #pragmas. Это включает в себя такие хитрости, как переименование или пересылка API.
Die in Sente 14.12.2008 20:22:06

Я не очень много работал с DLL, но, насколько я понимаю, для экспортированных функций C ++ вы должны использовать «__declspec (dllexport)», а для экспортированных функций C вы должны написать файл .def. Это возможно потому, что функции C ++ поддерживают перегрузку, а функции C - нет.

3
14.12.2008 06:41:58
Да. Возможность перегрузки = оформленные имена, которые раздражают указывать в файле .def. Здесь нет принципиальной разницы между C и C ++, но существует значительная эргономическая и культурная разница.
Jirka Hanika 4.07.2012 12:21:00

Файлы .DEF чаще встречались в 16-битных окнах, где они обычно были единственным способом указать, какие символы следует экспортировать.

Кроме того, они предоставили средства для определения экспорта по порядковому значению (@ 1, @ 2 и т. Д.), А не по имени. Этот метод поиска символов использовался, когда производительность была действительно важна, например, в видеодрайверах.

4
14.12.2008 14:41:04

Насколько я понимаю, файлы .def на самом деле не указывают, какие все apis нужно экспортировать. Он просто содержит экспортированные apis и их порядковые номера. Если вы действительно хотите экспортировать определенный API, вам нужно указать __declspec (dllexport) в определении API и __declspec (dllimport) в объявлении.

Преимущество файла def состоит в том, что он помогает поддерживать совместимость обратного слова с уже реализованными dll. т.е. он поддерживает порядковые номера для apis. Предположим, что вы добавляете новый API в DLL, затем компоновщик просматривает ваш файл .def, генерируя порядковый номер для ne wapi, так что порядковые номера для старого API остаются нетронутыми.

Таким образом, если код клиента использует последнюю версию DLL, он не нарушает существующий API-интерфейс.

3
14.12.2008 17:33:38

Для тех, кто еще заинтересован ... чтобы иметь возможность ссылаться на файл dll и def, вам также потребуется файл lib. В окнах это можно сделать из def с помощью инструмента «LIB». Ниже приведен пример того, как это сделать из командной строки.

lib /machine:i386 /def:sqlite3.def

Надеюсь, что это помогает другим.

10
18.12.2008 02:57:46
На самом деле, это не сработало. Что же работа была следующая команда: lib /DEF:sqlite3.def /MACHINE:X86 /SUBSYSTEM:WINDOWS /LTCG /NOLOGO. Получившийся .lib можно легко использовать для динамического связывания с sqlite3.dll.
fmuecke 17.04.2012 13:58:06

Я считаю, что использование __declspec (dllexport) и файла .def вместе полезно для создания переносимых DLL, то есть DLL, которые можно вызывать из кода, скомпилированного с другим компилятором или с другими настройками компилятора.

Простое добавление __declspec (dllexport) в ваши объявления функций приведет к тому, что эти функции будут «экспортированы» вашей DLL (по крайней мере, в Windows), чтобы их можно было вызывать извне DLL.

Однако добавление в сборку файла .def, в котором перечислены все ваши экспортируемые функции, позволяет запретить компиляторам Microsoft (например) добавлять начальную подчеркивание и конечную информацию о ширине параметра к имени экспортируемой функции (по крайней мере, в сочетании с __stdcall директива, также полезная для переносимости). Например, объявление функции

void foo(int i);

может закончиться тем, что будет экспортирован как "_foo @ 4", если вы не будете осторожны с соглашением о вызовах и использованием файла .def.

Сохранение экспортированных имен функций в таблице символов без таких украшений имен становится очень удобным, когда вызовы GetProcAddress () выполняются как часть загрузки и явного подключения к DLL во время выполнения. т.е. чтобы получить указатель на указанную выше функцию foo () (при условии, что она вообще была экспортирована) во время выполнения, в идеале вы просто хотите вызвать:

HANDLE dllHandle = LoadLibrary("mydll.dll");
void* fooFcnPtr = GetProcAddress(dllHandle, "foo");

С некоторой соответствующей проверкой ошибок, конечно!

Использование файла .def плюс __stdcall, __declspec (dllexport) и extern "C" в ваших объявлениях функций при сборке вашей DLL гарантирует, что вышеуказанный код на стороне клиента будет работать для широкого диапазона компиляторов и настроек компилятора.

24
28.02.2009 05:47:15
Чтобы предотвратить искажение имен функций C ++, вы должны объявить их как extern "C".
sbi 13.10.2015 12:40:39
@sbi, extern "C"не предотвратит искажение имени полностью, это предотвратит только искажение имени в C ++, оставляя искажение в C. Например, 32-битные компиляторы MSVC добавляют все эти @украшения stdcallи fastcallфункции, даже с extern "C".
Alex Che 27.08.2019 09:34:46
Другой альтернативой файлам .def является использование #pragma comment(linker, ...), например, как описано здесь
Alex Che 27.08.2019 09:39:05