24

我有一组静态编译的库,库之间具有相当深入的运行依赖关系。例如,可执行文件 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 部分的“附加依赖项”设置,添加 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" (_symbol) 已在 B.lib(c.obj) 中定义;第二个定义被忽略。

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

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

4

9 回答 9

15

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

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

另请阅读:

链接/忽略

MSDN 论坛 - 隐藏 LNK 警告

瓦切克

于 2009-02-27T13:45:14.023 回答
9

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

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

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

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


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

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

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

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

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

于 2009-02-25T23:01:18.433 回答
4

Microsoft (R) Incremental Linker Version 9.00.x ( link.exe ) 知道参数/ignore:4006

于 2009-02-27T16:00:44.527 回答
3

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

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

于 2009-02-24T20:38:17.847 回答
1

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

// Foo.h

class Foo
{
    void someFunction();
};

void Foo:someFunction() // Warning!  - should be "inline void Foo::someFunction()"
{
    // do stuff
}
于 2011-07-20T09:29:08.470 回答
0

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

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

于 2009-02-19T11:59:01.597 回答
0

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

于 2009-02-19T11:59:37.057 回答
-1

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

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

#pragma comment(lib:"wsock32") 

就像我说的那样,我不确定它是否会将符号保留在该目标文件中,我必须编写一个示例来尝试一下。

于 2009-02-25T23:19:54.660 回答
-3

可怜的 flodin 似乎很沮丧,因为没有人会解释如何禁用链接器警告。好吧,我也遇到过类似的问题,多年来我一直忍受着显示数百条警告的事实。然而,现在,感谢来自Link /ignore的信息,我想出了如何禁用链接器警告。

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

于 2010-08-15T00:27:33.630 回答