【问题标题】:VC8 to VC10 - LNK2005 errorsVC8 到 VC10 - LNK2005 错误
【发布时间】:2011-04-08 10:42:53
【问题描述】:

我最近安装了 Visual Studio 2010 并使用 CMake 为我的项目生成解决方案文件。这个过程以前在 VS2005 上运行良好。

我遇到的第一个问题是因为新的“移动构造函数”,所以我不得不从我的代码中删除一些隐式转换——这很公平,现在可以了。

我目前的情况如下:我正在编译DLL 1,它只依赖于一些系统库(Kernel32等)和CRT,以及DLL 2,链接到 DLL 1,以及一些第三方库。

我得到的错误大致如下:

DLL1.lib(DLL1.dll) : error LNK2005: "public: __thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::~basic_string<char,struct std::char_traits<char>,class std::allocator<char> >(void)" (??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ) already defined in objFromDLL2.obj

这似乎正是here 描述的问题。

但是,此线程中的任何内容都无法解决我的问题。

  • 我已经确认 DLL1 和 DLL2 都是使用 /MD 代码生成标志编译的,
  • DLL2 链接到 squish、glew 和 devil — 我已经手动重新编译了所有这些以及它们所依赖的任何库用于 VC10,也使用 /MD
  • edit 根据this article(与我的问题类似),我已删除从 std::containers 派生的类的所有实例
  • edit 我已经确认这不是第 3 方问题,因为我已经使用相同的库成功编译了另一个项目,但是我仍然无法编译我的原始项目
  • edit dllexport 正在我的代码中所有需要的地方使用

我错过了什么?如果我需要提供更多信息,请告诉我,我会尽我所能编辑问题。

更新:已经有一段时间了,我仍然没有解决方案。我一直在用对 cme​​ts 的响应来更新这个问题,我目前正在研究一个不同的代码库,它确实有效——我开始认为旧代码的向后兼容性终于开始枯竭,我应该只是继续前进。

更多更新: 我发现可能是一个非常不受欢迎的链接器标志,/FORCE:MULTIPLE,它通过忽略除了符号的第一个定义之外的所有内容,将错误变成警告。这样做肯定有不好的副作用。对该标志的测试突出显示了 LNK2001: unresolved std::string::npos,它隐藏在所有先前的 LNK2005 错误中。折磨永远不会结束。

【问题讨论】:

  • 您确定没有第三方库与其他库链接吗?
  • @dauphic Devil 使用了许多其他库,我也使用 VC10 编译了这些库。编辑问题以突出显示这一点。
  • 我最初的猜测是Devil链接的库使用不同的CRT链接;或者,您不小心在调试中构建了其中一个库。
  • 这可能是一个无用的评论,但我想知道您是否确保您的类和函数都使用 dllexport?当我没有正确使用它时,我遇到了类似的错误。
  • 这不是您链接到的问题。那是一个未定义的符号;你的被定义了两次。正确的定义数量当然是 1,但是缺少符号通常是一个更大的问题(重复的定义更容易合并)

标签: c++ visual-studio-2010 linker


【解决方案1】:

我已经成功使用/FORCE:MULTIPLE。有时在使用混杂的库时是不可避免的。只要链接器使用同一个地址来一致地解析引用,它就可以工作。其他定义被忽略。

【讨论】:

    【解决方案2】:

    我倾向于认为您陈述的假设是不正确的。特别是,“DLL 1,仅依赖于某些系统库(Kernel32 等)”如果使用 /MD 编译并引用 std::string::~string,则不可能正确。这显然会导致对 CRT 的依赖。

    另外,如果 DLL1 不依赖于 DLL2,那么链接器到底是如何知道来自 DLL2 的文件的?!您是否设法建立了循环依赖关系?

    在 VS2008 和 VS2010 之间,似乎 std::string::~string 已从 CRT 中删除。因此,它不再是您自己代码的 DLLimport。这可以解释行为上的差异。 DLL1 和 DLL2 之间的循环依赖关系对 std::string::~string 来说无关紧要,因为两者都会从 CRT 获取它,而这显然不是循环的一部分。

    【讨论】:

    • 您对 DLL1 的 CRT 依赖性是正确的 - 在我的描述中,我不明智地将它归类为“标准”。 DLL2 链接到 DLL1,这种依赖是单向的,因为 DLL1 不需要 DLL2,但 DLL2 确实需要 DLL1。链接器知道来自 DLL2 的文件,因为我正在编译/链接的是 DLL2,然后它会吐出 LNK2005 错误。
    • 啊,对。不明白你在链接什么;我把“DLL1.lib(DLL1.dll)”作为被链接的项目。
    • 不,链接器将其显示为多重定义符号的来源,但我实际上处于 DLL2 的链接器阶段。不过,关于删除 ~string 的有趣点,我可能会调查一下。
    【解决方案3】:

    问题似乎在于 DLL1 确实导出了 std::string(可能是隐式的,因为它在一个也被导出的类中使用),但 DLL1 的标头没有声明这一点。因此,在编译 DLL2 时,不会将其标记为导入。这没问题,因为它是一个模板:编译器只是实例化另一个副本。但随后链接器出错了,因为 DLL2 确实应该导入 std::string

    解决方案:显式导出/导入std::string;您可能已经在 DLL1 标头中为 _declspec( ) 提供了适当的宏。

    【讨论】:

    • 我关注了these instructions 并获得了预期的 C4231 警告,但 LNK2005 仍然存在。我做错了吗? EXPIMP_TEMPLATE 模板 DECLSPECIFIER std::string;
    猜你喜欢
    • 2011-10-01
    • 2023-03-31
    • 2012-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-30
    • 2010-10-11
    相关资源
    最近更新 更多