正确的方法链接静态库和动态链接库

24

我的项目通过几个静态库进行构建,这些库应该链接到主dll库中,以便作为结果获得一个单一的dll。

使用__declspec(dllexport)属性不会导致静态库的指定函数出现在dll中,根本没有将库链接到dll。

然后我尝试将每个库构建为共享库,以获取导出函数的正确名称,并基于它们创建.def文件。使用.def文件导致了结果。

  1. 在我的情况下,__declspec(dllexport).def文件应该起到同样的作用吗?

  2. 是否可以从源代码生成.def文件?由于我的代码是C++代码,我无法自己编写.def文件,因为需要进行名称修饰并包含API中的类,上述描述的使用临时生成的dll的方法对于生产来说不一致。

更新

我想详细解释一下我的项目结构。解决方案由几个项目(模块)组成。

+ 
|    
+-+ static_lib1                                          
|       +                                                
|       +--+ src                                         
|                                                        
+-+ static_lib2                                          
|       +                                                
|       +--+ src                                         
|                                                        
+-+ dynamic_lib (linked with static_lib1 and static_lib2)
        +                                                
        +--+ src
每个子项目都弱依赖于其他项目,为了清晰起见,我们假定它们之间没有联系。每个模块都有自己的公共接口。我希望将所有模块打包成一个动态库,所以我的构件是dynamic_lib.dll,但实际上静态库没有与它链接。

问题:你说“[...]根本没有与dll链接的库”。你在dynamic_lib另一个项目中遇到了错误,该项目正在使用dynamic_lib吗?这个错误是“未解决的外部[...]”吗? - Mateusz Grzejek
尝试在外部项目中使用dll库时出现“unresolved external(未解决的外部)”错误。 - triclosan
2个回答

21

静态库不应包含任何__declspec__attribute((dll...))之类的东西。它们只是由多个对象文件(通常为*.obj*.o)组成的单个文件。

要使用这样的库(无论是.exe还是.dll),您需要做的就是包含正确的头文件并链接它们 - 在Visual Studio中很容易。

首先,您需要知道:1)您的静态库放置在哪里以及2)它们的确切名称。转到项目属性,然后选择常规目标名称包含输出文件的名称,而输出目录指示您的.lib将放置在哪个文件夹中。

注意:此路径对于每个项目可能是不同的!对于多项目解决方案,我总是将其设置为公共路径,以避免配置问题。

现在,转到将使用此库(与其链接)的项目的属性。 转到链接器->输入,然后将您的.lib的名称添加到附加依赖项中(条目用分号分隔):

Linker input

您需要添加所有要链接的库。 另外,这些库所在的文件夹必须添加到链接器->常规->附加库目录中。 如果所有.lib都放置在同一个位置 - 很好,否则将它们复制到共享位置或将多个条目添加到附加库目录列表中。

最后一件事 - 记住,您还需要包含声明要使用的函数和对象的头文件。 这是基本的,我知道,但必须提到。


更新

尝试在外部项目中使用dll库时出现未解决的外部问题

您的问题与链接无关。问题在于您误解了静态库的链接确切操作

我猜测,被报告为“未解决”的函数并未被您的DLL使用,对吗? 但是您希望它们在其中,对吗?

当您的DLL引用外部内容(例如函数或变量)时,它会在链接时解析-连同所有依赖项一起。 但仅限于此。 如果您的静态库具有名为print_sample_string()的函数,但是您的DLL没有使用它,则不会将其附加到DLL映像中。 仔细思考这个问题-为什么应该这样做呢?

更重要的是-未明确导出的函数根本看不见。 函数默认具有外部存储-因此基本上它们是私有DLL的内容。

因此,直接回答您的问题 - 如果您需要从static_lib1.lib使用函数/变量,请将其附加到客户端应用程序中-就像您现在将其附加到DLL_EXP_IMP long CallFunctionFromA_Lib() { return some_function(); //this function is from static_lib1.lib }

在某个地方的.exe文件中:

long result = CallFunctionFromA_Lib(); //internally this will call function from static_lib1.lib

然而,我无法想象为什么你想这样做,而不是直接链接A.lib并直接使用它。


谢谢!但是我有相同的配置。我的问题是库不使用彼此的代码,每个库都是单独的模块,使用自己的公共接口,因此链接器会忽略其他静态库,除了主要的那一个。 - triclosan
请更新问题,提供关于您拥有哪些库、想要使用哪些其他库(以及是哪些),以及您遇到的错误的确切信息。我不明白“链接器忽略除主要库之外的其他静态库”是什么意思。 - Mateusz Grzejek

5

这里 Raymond Chan 解释了这种行为,最好的解决方法就是使用 def 文件。至于如何自动生成静态库的 def 文件 - 这个 讨论看起来是一个不错的起点。


链接已过期。 - Cinder Biscuits
@CinderBiscuits(链接现在可用) - Drew Dormann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接