Visual C下的dllimport /dllexport及静态库编译++
我迫切需要你的帮助。
我尝试使用 Visual C++ 2008 编译器在 Windows 上静态编译 poppler 库(特别是 qt4)。为了完成这个任务,我还需要静态编译一堆其他库作为 poppler 的依赖项。当我最终生成 poppler 的静态版本时,我在构建应用程序时遇到链接错误:
error LNK2019: unresolved external symbol "__declspec(dllimport)...
我已经添加了新的包含路径并链接了 poppler-qt4.lib 但无论如何我都会收到错误。 在寻找解决方案时,我在 stackoverflow
有了这些信息,我查看了库的包含文件(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 */
没有静态指令的示例(jpeg lib 中的 jconfig.h):
#if defined(_WIN32)
#if defined(libjpeg_EXPORTS)
#define JPEG_EXPORT __declspec(dllexport)
#else
#define JPEG_EXPORT __declspec(dllimport)
#endif
#else
#define JPEG_EXPORT
#endif
我的问题是:将项目的属性从动态更改为静态还不够,所以我也必须更改此标头?,如果这是真的,我可以在哪里定义这个新指令来区分静态编译和动态编译?
提前致谢。
I desperatly need your help.
Im trying to compile statically the poppler library (specially for qt4) on windows with the visual c++ 2008 compiler. To achieve this task I needed to compile a bunch of other libraries as dependencies for poppler statically too. When I finally generate the static version of poppler I got a linking error when building my app:
error LNK2019: unresolved external symbol "__declspec(dllimport)...
I already added the new include path and linked the poppler-qt4.lib but i get the error anyways.
Searching for a solution I found this discussion here in stackoverflow
How to link a static library in Visual C++ 2008?
whit this information I looked on the include files of the libraries (dependencies of poppler like zlib, libpng, cairo, ...) and I found, in various cases, that they don't have a preprocessor directive to especify the static version of the lib.
Example static directive (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 */
Example without static directive (jconfig.h from 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
My question is: Is not enough to change the properties of the project from dynamic to static so I have to change this headers too?, and if this is true, where can I define this new directives for making a difference between static or dynamic compilation?
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

发布评论
评论(2)
如果要将项目属性从动态链接更改为静态链接(如 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
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
首先请注意 Windows 根本没有任何动态链接。惊喜!相反,它使用 thunk。那么会发生什么:如果你创建一个符号 dllexport,它就有它的实际名称,与不是 dllexport 的名称相同。但是,它在目标文件中标记为导出。
另一方面,如果你说 dllimport,则名称会被更改,在 C 中,粗略地通过在名称前加上 __imp_ 来更改,在 C++ 中更令人讨厌。
现在,当您链接 DLL 时,您会得到一个 DLL(当然),但同时也会得到一个 LIB 文件。那是一个静态链接库。这是链接器可以处理的唯一类型。对于从 DLL 导出的每个符号,该 LIB 文件中都有一个 dllimport 符号,特别是带有 __imp_ 前缀或 C++ 的任何前缀。
因此,现在在程序或 DLL 中,您想要链接到您创建的 DLL,而不是针对导入 LIB。导入 LIB 例程是修补 DLL 中实际加载时间地址的 thunk。
因此,现在,如果您尝试通过简单地组合包含某些 dllexport 的 OBJ 文件来对 LIB.EXE 生成的 LIB 文件进行普通静态链接,如果引用是 dllimport,则会失败。因为当库实际上包含普通 function() 时,您正在引用 __imp_function() 。
因此,使用静态链接,您必须删除 dllimport。 AFAIK dllexport 是无关紧要的。请注意,这适用于库的客户端,而不是库本身。
这意味着什么?静态链接到一个库,然后动态链接到另一个库是完全可以的。事实上,默认情况下,Windows 上的静态链接会动态链接到 C 运行时和操作系统 DLL。所以规则是:客户端必须选择链接到库的方法,提供者应该提供两个版本。但要小心他们有不同的名字! (否则制作DLL的LINK将制作fred.LIB,LIB也将制作fred.LIB)
First please note Windows does not have any dynamic linkage at all. Surprise! Instead, it uses thunks. So what happens is: if you make a symbol dllexport, it has its actual name, the same name as if it were not dllexport. However it is marked in the object file for exporting.
If you say dllimport, on the other hand, the name is changed, in C roughly by prepending __imp_ to the name, more nasty in C++.
Now, when you link a DLL, you get a DLL (of course) but you also get a LIB file. That is a static link library. Which is the only kind the linker can handle. For each symbol exported from the DLL there is a dllimport symbol in that LIB file, in particular with __imp_ prefix or whatever for C++.
So now in a program or DLL you want to link to that DLL you made you link instead against the import LIB. The import LIB routines are thunks that patch up to the actual load time addresses from the DLL.
So now, if you try to do ordinary static linkage against a LIB file made by LIB.EXE by simply combining OBJ files which contained some dllexport, it will fail if the reference is a dllimport. Because you're refering to __imp_function() when the library actually contains plain function().
So with static linkage, you have to drop the dllimport. AFAIK dllexport is irrelevant. Note that this applies to the client of the library, not the library itself.
What does that mean? Well it is perfectly fine to statically link to a library which in turn dynamically links to another library. In fact by default static links on Windows dynamically link to the C runtime and OS DLLs. So the rule is: the client must chose the method of linking to a library, the provider should provide both versions. But take care they have different names!! (Otherwise the LINK making the DLL will make fred.LIB and the LIB will also make fred.LIB)