Компиляция dllimport /dllexport и статических библиотек под Visual C++
Мне отчаянно нужна твоя помощь.
Я пытаюсь статически скомпилировать библиотеку poppler (специально для qt4) в Windows с помощью компилятора Visual C++ 2008. Чтобы решить эту задачу, мне нужно было статически скомпилировать кучу других библиотек в качестве зависимостей для poppler. Когда я наконец-то сгенерировал статическую версию poppler, я получил ошибку компоновки при сборке приложения:
error LNK2019: unresolved external symbol "__declspec(dllimport)...
Я уже добавил новый путь включения и связал poppler-qt4.lib, но я все равно получаю ошибку. В поисках решения я нашел это обсуждение здесь в stackru
Как связать статическую библиотеку в Visual C++ 2008?
С помощью этой информации я посмотрел на включаемые файлы библиотек (зависимости от poppler, такие как zlib, libpng, cairo,...) и обнаружил, что в разных случаях у них нет директивы препроцессора для определения статической версии библиотека Пример статической директивы (openjpeg.h):
#if defined(OPJ_STATIC) || !(defined(_WIN32) || defined(WIN32) || defined(__WIN32__))
# define OPJ_API
# define OPJ_CALLCONV
#else
# define OPJ_CALLCONV __stdcall
# ifdef OPJ_EXPORTS
# define OPJ_API __declspec(dllexport)
# else
# define OPJ_API __declspec(dllimport)
# endif /* OPJ_EXPORTS */
#endif /* !OPJ_STATIC || !WIN32 */
Пример без статической директивы (jconfig.h из jpeg lib):
#if defined(_WIN32)
#if defined(libjpeg_EXPORTS)
#define JPEG_EXPORT __declspec(dllexport)
#else
#define JPEG_EXPORT __declspec(dllimport)
#endif
#else
#define JPEG_EXPORT
#endif
У меня вопрос: не достаточно ли изменить свойства проекта с динамического на статический, поэтому я должен изменить и эти заголовки? И, если это так, где я могу определить эти новые директивы для различий между статической или динамической компиляцией??
Заранее спасибо.
2 ответа
Прежде всего, обратите внимание, что в Windows вообще нет динамической связи. Сюрприз! Вместо этого он использует thunks. Итак, что происходит: если вы создаете символ dllexport, он имеет его фактическое имя, такое же имя, как если бы это был не dllexport. Однако это отмечено в объектном файле для экспорта.
Если вы говорите, что dllimport, с другой стороны, имя изменяется в C примерно, добавляя __imp_ к имени, более неприятное в C++.
Теперь, когда вы связываете DLL, вы получаете DLL (конечно), но вы также получаете файл LIB. Это статическая библиотека ссылок. Который является единственным видом, с которым может работать компоновщик. Для каждого символа, экспортируемого из DLL, в этом файле LIB есть символ dllimport, в частности с префиксом __imp_ или любым другим для C++.
Итак, теперь в программе или DLL вы хотите связать с той DLL, которую вы сделали, вместо ссылки на LIB импорта. Процедуры импорта LIB - это блоки, которые исправляют фактические адреса времени загрузки из DLL.
Так что теперь, если вы попытаетесь выполнить обычное статическое связывание с файлом LIB, созданным LIB.EXE, путем простого объединения файлов OBJ, содержащих некоторый dllexport, произойдет сбой, если ссылка является dllimport. Потому что вы ссылаетесь на __imp_function(), когда библиотека фактически содержит обычную функцию ().
Так что со статической связью, вы должны отбросить dllimport. AFAIK dllexport не имеет значения. Обратите внимание, что это относится к клиенту библиотеки, а не к самой библиотеке.
Что это значит? Ну, это прекрасно для статической ссылки на библиотеку, которая в свою очередь динамически связывается с другой библиотекой. Фактически по умолчанию статические ссылки в Windows динамически связываются с библиотеками времени выполнения C и ОС DLL. Таким образом, правило таково: клиент должен выбрать метод связи с библиотекой, поставщик должен предоставить обе версии. Но позаботьтесь, чтобы у них были разные имена!! (В противном случае LINK, создающий DLL, создаст fred.LIB, а LIB также создаст fred.LIB)
Если вы изменяете свойства проекта с динамического на статическое связывание, как указано в openjpeg.h, вы должны указать препроцессор, который может использовать статическое связывание..так кроме изменения свойства с динамического на статическое, добавьте препроцессор OPJ_STATIC..,
Например:
#if defined(_WIN32)
#if defined(OPJ_STATIC)
# define OPJ_CALLCONV __stdcall
#el if defined(libjpeg_EXPORTS)
#define JPEG_EXPORT __declspec(dllexport)
#else
#define JPEG_EXPORT __declspec(dllimport)
#endif
#else
#define JPEG_EXPORT
#endif