__declspec(dllexport) 静态链接库到 dll

Posted

技术标签:

【中文标题】__declspec(dllexport) 静态链接库到 dll【英文标题】:__declspec(dllexport) static linked libraries to dll 【发布时间】:2020-04-07 23:43:28 【问题描述】:

我有一个用于大学的 OpenGL 项目的简单项目设置。

我想使用的每个库(GLEW、GLFW、GLM)都是静态链接的 API 项目。这些库应该与我自己的 API 代码组合成一个 DLL 文件。

另一个项目应该只有一个依赖项,即 DLL。抛出该 DLL,它应该可以访问 API 代码和 API 内链接的所有库。

我的问题是,在 API 中,我可以访问我链接的所有库的所有函数。但是在将 API 作为依赖项的实际项目中,我可以调用函数并且编译器不会抛出任何错误(原因),因为函数声明在链接的头文件中,但链接器在DLL,这意味着 API 的构建不会将链接的库导出到 DLL 中。

在 API 项目中,我还定义了必要的预处理器定义:

我定义了_GLFW_BUILD_DLL:

from "glfw3.h" l. 233-245

/* GLFWAPI is used to declare public API functions for export
 * from the DLL / shared library / dynamic library.
 */
#if defined(_WIN32) && defined(_GLFW_BUILD_DLL)
    /* We are building GLFW as a Win32 DLL */
    #define GLFWAPI __declspec(dllexport)         <----- this one is active
#elif defined(_WIN32) && defined(GLFW_DLL)
    /* We are calling GLFW as a Win32 DLL */
    #define GLFWAPI __declspec(dllimport)
#elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL)
    /* We are building GLFW as a shared / dynamic library */
    #define GLFWAPI __attribute__((visibility("default")))
#else
    /* We are building or calling GLFW as a static library */
    #define GLFWAPI
#endif

我定义了GLEW_BUILD:

from "glew.h" l. 200-208

#ifdef GLEW_STATIC
    #define GLEWAPI extern
#else
    #ifdef GLEW_BUILD
        #define GLEWAPI extern __declspec(dllexport) <---- this one is active
    #else
        #define GLEWAPI extern __declspec(dllimport)
    #endif
#endif

有什么帮助吗?

编辑:

链接器选项:

/OUT:"D:\Programmierung\C++-Projekte\CG-Project\CGAPI\bin\Debug\Win32\CGAPI.dll" /MANIFEST /NXCOMPAT /PDB:"D:\Programmierung\C++-Projekte\CG-Project\CGAPI\bin\Debug\Win32\CGAPI.pdb" /DYNAMICBASE "glew32s.lib" "glfw3.lib" "opengl32.lib" "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /IMPLIB:"D:\Programmierung\C++-Projekte\CG-Project\CGAPI\bin\Debug\Win32\CGAPI.lib" /DEBUG /DLL /MACHINE:X86 /INCREMENTAL /PGD:"D:\Programmierung\C++-Projekte\CG-Project\CGAPI\bin\Debug\Win32\CGAPI.pgd" /SUBSYSTEM:WINDOWS /MANIFESTUAC:NO /ManifestFile:"D:\Programmierung\C++-Projekte\CG-Project\CGAPI\bin-int\Debug\Win32\CGAPI.dll.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /LIBPATH:"D:\Programmierung\C++-Projekte\CG-Project\Dependencies\GLFW\Win32\lib-vc2019\" /LIBPATH:"D:\Programmierung\C++-Projekte\CG-Project\Dependencies\GLEW\lib\Release\Win32\" /TLBID:1 

我添加的那个:

/WHOLEARCHIVE:glew32s.lib
/WHOLEARCHIVE:glfw3.lib
/WHOLEARCHIVE:opengl32.lib

编辑 2:

所以我不得不从 glew 下载源代码并自己构建它,而且我必须在我自己的 glew 构建选项中删除 .res 文件。现在 API 构建成功,但方法不是 DLL 的一部分。所以什么都没有改变。

【问题讨论】:

当您构建 DLL 时,您还将(或应该)生成一个 import library - 这在某些方面看起来像一个静态库(在 Windows 上,它会有.lib 扩展名)。在构建调用 DLL 的应用程序时,您必须确保链接器包含此库,因为这会告诉链接器相关函数已从 DLL 加载(在运行时)。 我已经这样做了。所以我可以使用我自己编写的 API 代码。那里的原因链接器不会引发任何 LNK2019 错误。但是,当我想调用静态链接库中的函数 glfwMakeContextCurrentglewInit 时,链接器找不到它们,这意味着它们不是 DLL 或链接器包含的较小 LIB 的一部分。跨度> 啊,好的 - 明白了。我需要再考虑一下……现在是睡觉时间,所以我会在几个小时后回来。 (或者其他人可以帮忙。) 在构建 DLL 时,您可能必须在 Module Definition File 中将函数列为 EXPORTS。不过,不确定这是否足以让 EXE 知道它们在该 DLL 中。 这是个坏主意。如果您的 DLL 的用户也使用 OpenGL DLL 怎么办?通常的方法是简单地将 GL DLL 与您的 DLL 一起重新分发。 【参考方案1】:

我不完全理解你这样做的动机。常见的方法(我也会使用)是将 OpenGL .dlls(我不知道许可含义)与您的一起提供。

然而,即使这看起来像一个XY 问题,为了实现您的目标,您也可以将[MS.Docs]: /WHOLEARCHIVE (Include All Library Object Files) 传递给链接器。为了区分要包含哪些 .lib,请为每个目标库指定一次标志:/wholearchive:glew32.lib /wholearchive:glfw3.lib /wholearchive:glm.lib

查看[SO]: Exporting symbols in static library that is linked to dynamic library (@CristiFati's answer)了解更多详情。

请注意:.lib 必须是使用可导出符号构建的。如果没有,您必须使用其他选项之一“手动”导出它们:

/EXPORT 链接器选项 模块定义 (.def) 文件

或将 .lib 重建为静态但带有可导出符号。但是,它很有可能不起作用OOTB(您可能需要修改一个或 2 个文件或手动传递编译标志),因为这不是一种正常的方式(大多数人会同意这是一个NO-NO,尤其是对于那些没有相当深厚的专业知识的人)做事。

【讨论】:

所以我添加了 /WHOLEARCHIVE 选项。现在我遇到 LNK2005 错误,user32.libgdi32.lib 想要重新定义 __NULL_IMPORT_DESCRIPTOR 已经在 kernel.lib 中定义 现在我收到了 glew32s.lib 已指定的错误,因为我将 LIB 添加为附加依赖项。所以在链接器选项中,有一个名为/DYNAMICBASE 的选项已经指定了glew32s.lib。然后我尝试用标志 /WHOLEARCHIVE 重新指定它 /dynamicbase 不需要任何名称。也许您应该将链接器命令放在问题中。 好的,添加的 3 个库中的一个似乎与开头指定的库不匹配。也缺少链接器输出(错误)。还缺少一些其他的东西,所以坦率地说,我不确定这应该如何进行,因为我不想通过 cmets 询问每一个小信息和调试。 我可以上传项目吗?

以上是关于__declspec(dllexport) 静态链接库到 dll的主要内容,如果未能解决你的问题,请参考以下文章

__declspec(dllexport)

转载 __declspec(dllexport) 和__declspec(dllimport)

__declspec(dllexport) 和 __declspec(dllimport)的区别

如何在 stl 模板中使用导出的类 (__declspec(dllexport))?

MFC dll def文件和_declspec(dllexport)问题

使用可见性属性(没有 __declspec(dllexport))时,Clang 可以生成导入库吗?