在不获取LNK4006的情况下,将库与Visual C ++中的依赖项链接起来

时间:2009-02-19 11:29:32

标签: visual-c++ module warnings

我有一组静态编译的库,这些库之间存在相当深入的依赖关系。例如,可执行文件X使用库A和B,A使用库C,B使用库C和D:

X -> A
     A -> C
X -> B
     B -> C
     B -> D

当我将X与A和B链接时,如果C和D也未添加到库列表中,我不希望出现错误 - A和B在内部使用这些库的事实是X的实现细节不应该知道。此外,当在依赖关系树中的任何位置添加新依赖项时,必须重新配置使用A或B的任何程序的项目文件。对于深度依赖树,所需库的列表可能变得非常长且难以维护。

所以,我正在使用A项目中Librarian部分的“Additional Dependencies”设置,添加C.lib。在B项目的同一部分,我添加了C.lib和D.lib。这样做的结果是图书馆员将C.lib捆绑成A.lib,将C.lib和D.lib捆绑成B.lib。

然而,当我链接X时,A.lib和B.lib都包含他们自己的C.lib副本。这导致了大量的警告

  

A.lib(c.obj):警告LNK4006“符号”(_symbol)已在B.lib(c.obj)中定义;第二个定义被忽略了。

如何在不收到警告的情况下完成此操作?有没有办法简单地禁用警告,还是有更好的方法?

编辑:我看到不止一个答案表明,由于缺乏更好的替代方案,我只是禁用警告。嗯,这是问题的一部分:我甚至不知道如何禁用它!

9 个答案:

答案 0 :(得分:11)

据我所知,您无法禁用链接器警告。 但是,您可以使用链接器的命令行参数来忽略其中一些,例如。 /忽略:4006

将它放在链接器 - >命令行设置下的项目属性中(不记得确切的位置)。

另请阅读:

Link /ignore

MSDN Forum - hiding LNK warnings

Wacek

答案 1 :(得分:8)

更新如果您可以在单个解决方案中构建所有涉及的项目,请尝试以下方法:

  • 将所有项目放在一个sln。
  • 从项目的链接器或库管理器属性中删除对静态库的所有引用。
  • 解决方案资源管理器中每个项目的上下文菜单中都有“项目依赖项...”选项。用它来定义项目之间的依赖关系。

它应该工作。它不会使我之前说过的任何内容失效,构建C / C ++程序的基本模型保持不变。 VS(至少2005和更新版本)非常智能,可以将所有需要的静态库添加到链接器命令行。您可以在项目属性中看到它。

当然,如果您需要使用已编译的静态库,此方法将无济于事。然后你需要将它们全部添加到直接或间接使用它们的exe或dll项目中。


我认为你无能为力。您应该从静态库项目中删除对其他静态库的引用,并添加所有需要的静态库项目作为exe或dll项目的依赖项。您将不得不忍受任何包含A.lib或B.lib的项目都需要包含C.lib的事实。

作为替代方案,您可以将库转换为dll,从而提供更丰富的模型。

静态编译的库根本不是具有依赖性信息等的真实库,如dll。了解在构建它们时,您真的不需要提供它们所依赖的库吗?标题就是所需要的。看到?你甚至不能说静态库依赖于某些东西。

静态库只是已编译但尚未链接的目标代码的归档。它并不完整。每个目标文件都是单独编译的,并且在库中保持独立的实体。构建exe或dll时会发生链接。那是你需要提供所有目标代码的时候。这就是所有符号和依赖关系解决的时候。

如果将其他静态库添加到静态库依赖项,则库管理器将简单地将所有代码复制到一起。然后,在构建exe时,链接器会给你很多关于重复符号的警告。您可能能够阻止这些警告(我不知道如何),但要小心。它可能隐藏真正的问题,例如具有不同定义的真实重复符号。如果您在库中定义了静态数据,那么它可能无论如何都无法工作。

答案 2 :(得分:3)

您可以创建一个包含A,B,C和C的库。 D然后将X链接起来。

由于它是一个库,因此只有实际引用的对象模块才会链接到最终的可执行文件中。

答案 3 :(得分:3)

Microsoft(R)增量链接器版本9.00.x( link.exe )知道参数 / ignore:4006

答案 4 :(得分:1)

请注意,获取此警告的一种方法是在没有内联语句的标头中定义成员函数:

// Foo.h

class Foo
{
    void someFunction();
};

void Foo:someFunction() // Warning!  - should be "inline void Foo::someFunction()"
{
    // do stuff
}

答案 5 :(得分:0)

问题是您没有本地化库C的符号。因此,当您在A和B中进行链接时,您会遇到ODR违规。您需要有办法将这些内容设为私有。默认情况下,将导出所有符号。一种方法是为A和B提供一个特殊的链接器定义文件,明确提到需要导出哪些文件。

[1] ODR =一个定义规则。

答案 6 :(得分:0)

我认为这里最好的做法是忽略/禁用链接器警告(LNK4006),因为C.lib需要成为A.Lib和B.lib的一部分,而A.Lib不需要知道B.lib本身使用C.Lib。

答案 7 :(得分:-1)

这可能无法解决您的链接错误,但它可能有助于您的依赖关系树问题。

我所做的只是使用#pragma在需要它的.cpp文件中包含一个lib。例如:

#pragma comment(lib:"wsock32") 

就像我说的那样,我不确定它是否会将符号保留在该目标文件中,我不得不用一个例子来试一试。

答案 8 :(得分:-3)

可怜的flodin似乎很沮丧,没有人会解释如何禁用链接器警告。好吧,我遇到了类似的问题,多年来我一直怀着几百个警告的事实。但是,现在,感谢来自Link /ignore的信息,我想出了如何禁用链接器警告。

我正在使用Visual Studio 2008.在Project - >设置 - >配置属性 - >图书馆员 - >命令行 - >其他选项,我添加了“/ ignore:4006”(没有引号)。现在我的警告消失了!