C++ 如何避免;LNK2005已定义错误“;如果两个静态库使用相同的另一个静态库?

C++ 如何避免;LNK2005已定义错误“;如果两个静态库使用相同的另一个静态库?,c++,visual-c++,cmake,linker,C++,Visual C++,Cmake,Linker,情况: 静态库LIB1,从源代码编译并链接为LIB1.lib(带/MD)。 使用库LIB2并具有LIB2.lib中的内部对象 静态库LIB2,也使用/MD编译 (不是直接)依赖于两个库的EXE 在MSVC 15.9.19上链接此EXE的结果:许多LNK2005错误,如 lib2.lib: error LNK2005: "function <funcsig> already defined in lib1.lib" lib2.lib:错误LNK2005:“函数已在lib1.lib

情况:

  • 静态库LIB1,从源代码编译并链接为LIB1.lib(带/MD)。 使用库LIB2并具有LIB2.lib中的内部对象
  • 静态库LIB2,也使用/MD编译
  • (不是直接)依赖于两个库的EXE
在MSVC 15.9.19上链接此EXE的结果:许多LNK2005错误,如

lib2.lib: error LNK2005: "function <funcsig> already defined in lib1.lib"
lib2.lib:错误LNK2005:“函数已在lib1.lib中定义”
我也收到很多警告,比如

lib1.lib: warning LNK4099: PDB 'lib2.pdb' was not found with 'lib1.lib' or at '<path>'; linking object as if no debug info
lib1.lib:警告LNK4099:在“lib1.lib”或“”处未找到PDB“lib2.PDB”;链接对象,好像没有调试信息
问题:为什么链接器不合并重复的定义?如何诊断此问题的确切原因

谢谢

更新: 这些错误与标准库无关。它们是关于Google Protobuf函数的。LIB2是谷歌的libprotobuf.lib。LIB1也是使用Protobuf的谷歌工具库。但我们也使用Protobuf,因此产生了冲突

这几乎肯定会有所帮助

正如您所说,这些不是标准的C/C++函数,您可以忽略关于混合调试和发布代码的部分。不幸的是,这仍然给你留下了很多可能的原因。这是一个很好的排除

如果在使用/clr选项时混合使用静态库和动态库,则可能会发生此错误

如果在编译时查看命令行选项,请打开或检查每个文件的属性

一旦排除了这一点,所有其他原因都是您实际上声明了相同的东西(函数/变量)两次。最有可能发生这种情况的方法是在头文件中放入某些内容(如函数),该头文件包含在多个模块文件中。在没有看到代码的情况下进行诊断是很困难的。您必须选择其中一个错误,并选择名称中不属于人类可读位的部分。然后,您需要检查声明它的位置,并查看它是否位于标头中。如果不是,则必须包含源文件中的非标头。查找文件包含位置的一种快速(且不干净)方法是向文件中添加一个文件,然后一次重新编译一个文件,以查看何时打印该文件。要了解它为什么包含在使用中

如果符号是从头文件声明的,则必须通过将其设置为。 如果你不知道怎么做,我建议你开始一个新的问题,大致是“我如何转发声明?”。它会很快给你答案


希望这能有所帮助。

似乎LIB1正在做出不应该做出的假设。它不应该与另一个静态库链接,或者不应该从该库导出任何符号。如果使用链接器选项会发生什么情况?Does/FORCE:多重帮助?要告诉链接器使用默认库以外的库,请在命令行上指定要使用的库,并使用/NODEFAULTLIB选项禁用默认库。在IDE中,添加对项目的引用以指定要使用的库,然后打开项目的“属性页”对话框,并在链接器的“输入属性页”中,设置“忽略所有默认库”或“忽略特定默认库”属性以禁用默认库。这将有助于了解“funcsig”是什么。具体来说,它是来自代码还是来自CRT(C运行时库)。如果它是一个CRT函数,很可能您没有正确设置/MD标志。如果没有,则库之间有重复符号。发生这种情况最明显的方式是在头中使用非内联函数。@1201programalm:/NODEFAULTLIB:LIB2没有帮助,仍然是相同的错误消息这是一个很好的答案,谢谢。不幸的是,这对我帮助不大。1) 我不使用/clr选项。2) 如果Protobuf的头文件违反了ODR,那么这个库实际上是不可用的,但它是Google自己非常流行的库。基本上,错误来自这样一个事实,即Or工具库(LIB1)不应该从Protobuf重新导出符号,但它确实如此。我希望有人能给我建议如何避免这种情况。库是对象文件(归档)的容器。对象文件来自模块文件。如果您在状态中使用静态链接,则必须在模块中创建重复的函数。DLL不“导出”符号。它使用具有相同名称的静态函数镜像动态加载的符号(未链接)。它们加载动态函数并调用它们。(这被称为thunk'ing)。是否可能是您无意中使用了DLL。看这里