dllexport неожиданно не вызывает ошибку компоновщика в ссылочном проекте - PullRequest
1 голос
/ 03 марта 2020

Я столкнулся с некоторым поведением, которое, насколько я понимаю, должно вызвать ошибку компоновщика.

У меня есть два проекта C ++ MyLib и MyLibTests . MyLib - это проект windows dll. В этом проекте есть заголовочный файл Declspe c .h

// Declspec.h
#pragma once
#define NATIVE_API __declspec(dllexport)
#define NATIVE_API_CALL __cdecl

, который используется для аннотирования функций, которые должны быть экспортированы (для их проверки).

Теперь есть несколько заголовочных файлов, которые объявляют функции, например GUID.h (я вырезал ненужные части):

// GUID.h
NATIVE_API GUID newGuid();

и связанные с ними исходные файлы, например GUID. cpp:

// GUID.cpp
GUID newGuid()
{
    GUID g;
    (void)CoCreateGuid(&g);
    return g;
}

MyLib builds GUID. cpp и пока все в порядке. Теперь MyLibTests ссылается на dll и вызывает функцию newGuid(). Для этого тот же GUID.h включен в MyLibTests . Код компилируется, и похоже, что он работает правильно. Это точка, которую я не понимаю. Включая GUID.h , мы транзитивно включаем Declspe c .h , который разрешает макрос NATIVE_API в __declspec(dllexport), что означает, что функция должна быть снова экспортирована (что само по себе уже неправильно). Я предположил, что dllexport требует, чтобы определение было доступно в одной из единиц перевода (а именно GUID. cpp здесь), чтобы разрешить экспорт. Но поскольку GUID. cpp является , а не , созданным как часть проекта MyLibTests , я ожидаю ошибку компоновщика вместо успешной сборки.

Насколько я знаю, Declspe c .h выглядит следующим образом:

// Declspec.h
#ifdef SOME_PROJECT_DEPENDEND_MACRO
#   define NATIVE_API __declspec(dllexport)
#else
#   define NATIVE_API __declspec(dllimport)
#endif

и SOME_PROJECT_DEPENDEND_MACRO, являющиеся макросом, объявленным в файле проекта проект, который обеспечивает функцию. Таким образом, все включенные в определяющий проект получают подпись dllexport, в то время как все ссылающиеся проекты включают заголовочные файлы с подписью dllimport (и, следовательно, не ищут определения внутри своих собственных модулей перевода).

Почему оба проекта успешно компилируются (и выполняются), несмотря на то, что все функции всегда dllexport ed в обоих проектах?

1 Ответ

0 голосов
/ 03 марта 2020

Большинство компиляторов имеют возможность создавать только предварительно обработанный файл, вместо фактической компиляции и создания объектного файла.

Например, для компилятора Visual Studio предусмотрена опция / E . Затем вы можете проверить предварительно обработанный файл, чтобы увидеть, что NATIVE_API на самом деле предварительно обрабатывается в ваших исходных файлах теста. В сочетании с другими опциями вы можете записать вывод препроцессора в файл и проверить его. Может быть, определение приходит откуда-то еще по сравнению с тем, откуда вы ожидаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...