如何嵌入静态库的副本?

How to embed copies of static library?

这是我的解决方案的结构:

A.lib 定义:

int a(void) { return 1; }

B.lib定义:

int b(void) { return a(); }

C.lib定义:

int c(void) { return a() * 2; }

SharedStaticLibsTest.exe 定义:

int main(void) { std::cout << b() + c() << std::endl; return 0;}

我决定检查(通过 DumpBin)结果应用程序中嵌入的代码。结果是 BC 库使用了 A 库的唯一实例。有没有办法(出于教育目的)在 BC 中使用两个不同的 A 实例?也许这个东西有特定的链接器选项?我明白,这种行为可能会产生意想不到的副作用,这取决于 A 库的逻辑。

P.S。我通过在项目属性中直接包含 .lib 文件来替换对项目的引用。现在 BC 个项目有 A 个项目的副本。但最终项目仍然只有 A 库的副本。我不知道链接器是如何解决这个问题的。

首先,如果您最终在构建中有两个 A 实例,则从 A 导出的所有标识符都需要遵循 One-Definition-Rule.

也就是说,即使您在技术上可以拥有两个不同版本的 A,除非它们在所有意图和目的上都相同,否则您的程序是无效的,无论是编译器还是 linker有义务告诉您(C++ 标准称此 格式错误,不需要诊断 )。在实践中,这意味着您的程序中将有 非常 个奇怪的错误,并且不知道它们来自哪里。

话虽如此,从技术上讲,没有什么能阻止您构建您所要求的情况。通常静态依赖只在 linking 阶段被处理。因此,依赖于另一个静态库 A 的静态库 B 不会导致一个从另一个导出符号 - B 将不包含来自 A.[= 的任何符号39=]

相反,您的构建系统将跟踪该依赖关系,一旦您到达 linker 阶段(例如,通过构建依赖于 B 的可执行文件),构建系统将采取注意 两个 库都得到 linked。这也意味着,如果您没有构建系统,或者您的构建配置不正确,您将收到 linker 错误,因为缺少 A 库中的符号,即使您 link 明确反对 BC

因此,复制符号的规范、可移植方式需要通过 动态库 将它们拉入,因为它们会通过 linker。如果您将 BC 更改为动态库,它们都将 link 反对 A 并包含它们自己使用的来自 A 的函数的单独版本。如果您在构建 BC 之间更改了 A,它们将包含不同的定义。希望您的构建系统会尝试防止这种情况发生。 请注意,C++ 标准并没有太多关于动态库的内容,因此有关如何在此处解析符号以及重复符号的影响的技术细节,请参阅您的操作系统手册。

使用 MSVC,还可以为静态库执行此操作。在 BC 的项目属性中,前往 Librarian -> General 并设置 Link 库依赖项 选项 Yes。现在,如果您重新构建并再次查看 B.libC.lib 的转储,它们应该也包含来自 A 的符号。当然,在构建生成的可执行文件时,linker 将从 BC 中选择版本(或者直接从 A 中选择版本,具体取决于您的方式linking) 对于正在使用的每个 A 符号。请不要在生产中这样做。