15

当我链接我的项目时,我收到了这个错误,

COMMUNICATION.obj:致命错误 LNK1179:文件无效或损坏:重复 COMDAT '_IID_IXMLDOMImplementation'

问题的根源是什么?

4

8 回答 8

42

这是一个棘手的问题。

问题是生成的符号太长,并且存在歧义:

  //...
  void MyVeryLongFunctionNameUnique_0(void);
  void MyVeryLongFunctionNameUnique_1(void);
  //   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  //   (example max-symbol-length-seen-by-linker)

在这种情况下,链接器将这两个函数“视为”“相同”,因为使它们“唯一”的部分比最大符号长度长。

至少在三种情况下会发生这种情况:

  • 您的符号名称“太长”而不能被认为是链接器独有的,但对于编译器来说可能没问题(例如当您从许多嵌套模板中展开时)
  • 你做了一些无效 C++ 的“诡计”,它通过了编译器,但你现在有一个 invalid *.obj,它阻塞了链接器。
  • 您指定了重复的“未命名”类/结构,链接器无法解析它们。
  • ===[UPDATE]===,这不是你的错,这是编译器和/或链接器的内部问题(有关可能的解决方法,请参见下文)。

根据问题(以上),您可以“增加”符号长度(通过限制符号长度的减少),或修复代码以使其有效(明确)C++。

此错误(最低限度)由 Microsoft 在以下位置描述:

注意:此最大符号长度可以使用/H选项设置,请参阅:http: //msdn.microsoft.com/en-us/library/bc2y4ddf (v=vs.90).aspx

  • 建议: 检查是否/H在您的命令行上使用 。如果是,则删除它(不指定max-symbol-length,默认为2,047/H只能减少这个长度,不能增加它)。

但是,您可能通过/Gy选项(函数级链接)触发了它,这可能是通过 、 或 之一暗示的/Z7/Zihttp /ZI: //msdn.microsoft.com/en-us/library/958x11bc(v=vs. 90).aspx

一个讨论此问题的 MSDN 线程是:

该线程表明可以使用“invalid-C++-code-that-c *.obj​​ompiles”(你得到你的)触发这个问题,但是这会*.obj导致链接器无效(这个例子试图main同时用作函数和模板) :

===[更新]===

我之前应该这么说,因为我怀疑,但我现在有更多信息:这可能不是你的错,编译器和/或链接器中似乎存在触发此错误的问题。尽管事实上你所有失败的关系中唯一的共同点是你。

回想一下“上面的列表”适用(这可能是你的错)。但是,在“这不是你的错”的情况下,这里是当前运行列表(我相信这个列表不完整)。

  • *.ilk您的文件(中间链接文件)中存在内部错误/损坏。删除它并重建。
  • 您已/INCREMENTAL打开链接,但不知何故增量链接不适用于您的项目,因此您应该将其关闭并重建(Project-Properties=>Configuration Properties=>Linker=>General=>Enable Incremental Linking[设置为“否”(/INCREMENTAL:NO)]
  • 您使用的“COMDAT 折叠”的“优化”有问题。您可以通过转到“删除冗余 COMDATs” Project Proerties=>Configuration Properties=>Linker=>Optimization=>Enable COMDAT Folding,设置为“删除冗余 COMDATs ( /OPT:ICF)

这是一个有趣的线程,他有时可以链接,有时不能,通过注释/注释几行代码。问题不是代码——他只是无法一致地链接,而且看起来编译器和/或链接器在一些晦涩的用例下存在内部问题:

来自非平凡网络搜索的其他观察结果:

  • 这个问题似乎并不罕见
  • 它似乎与某种形式的template<>使用有关
  • 当“调试”构建没有这个问题时,其他人似乎在“发布”构建中看到了这个问题(但在许多情况下,它也出现在“调试”构建中)
  • 如果链接在一台机器上“失败”,它可能在另一台构建机器上“成功”(不知道为什么,“干净构建”似乎没有效果)
  • 如果您注释/注释掉特别重要的几行代码,并完成构建,并继续这样做,直到所有代码再次取消注释,您的链接可能会成功(这似乎是可重复的)
  • 如果您在使用 MSVC2008 时遇到此错误,并且将代码移植到 MSVC2010,您仍然会收到此错误

===[给世界好人的请愿书]===

如果您对此错误有其他意见,请在下面列出(作为其他答案,或作为此答案下方的评论)。我有一个类似的问题,这不是我的错,而且这些变通方法都不适合我(尽管在某些情况下它们似乎确实适用于他们的项目中的其他人)。

我正在增加赏金,因为这让我发疯。

===[更新+2]===

(叹气),这里有更多要尝试的东西(显然对其他人有用,但对我不起作用):

  • 这家伙改变了他的编译设置,它工作了(来自http://forums.codeguru.com/showthread.php?249603.html的线程):

    Project->Settings->C++ tab, Debug cathegory: Inline function expansion: 从 ' None' 更改为 ' Only _inline'。

  • 上面的线程引用了另一个必须重新安装 MSVC 的线程

  • 它可能与在可能不兼容的编译器和/或链接开关中链接具有“细微差异”的模块有关。检查所有“贡献库”是否使用完全相同的开关构建

以下是有关此错误/错误的更多症状/观察结果:

  • 上述问题的清单仍然适用
  • 该问题似乎在 MSVC2005 中“开始出现”,并且在 MSVC2008 和 MSVC2010 中继续出现相同的行为(将代码移植到较新的编译器后仍然会出现错误)
  • 重新启动IDE,重新启动机器似乎对任何人都不起作用
  • 一个人说明确的“清理”然后重新编译对他有用,但许多其他人说这对他们不起作用
  • 通常与“增量链接”有关(例如,将其关闭)

状态:不开心。

===[更新+3:链接成功]===

超级古怪的无意义修复成功发现链接!

这是(上图)的一个变体,您可以在其中“摆弄代码直到编译器和/或链接器行为”。不好的是可能需要这样做。

特定的单个链接器错误 ( LNK1179) 用于MyMainBody<>()

#include "MyClassA.hpp"
#include "MyClassB.hpp"
#include "MyClassC.hpp"
#include "MyClassD.hpp"
#include "MyMainBody.hpp"

int main(int argc, char* argv[])
{
  // Use a function template for the "main-body", 
  // implementation is "mostly-simple", instantiates 
  // some local "MyClass" instances, they reference 
  // each other, and do some initialization,
  // (~50 lines of code)
  //
  // !!! LNK1179 for `MyMainBody<>()`, mangled name is ~236 chars
  //
  return MyMainBody<MyClassA,MyClassB,MyClassC,MyClassD>(argc,argv);
}

修复:

  • MyMainBody<>()从 " template<>"转换为显式函数 LINK SUCCESS

这个 FIX SUX,因为我需要 EXACT-SAME-CODE 用于其他实用程序中的其他类型,并且MyMainBody<>()实现是非平凡的(但大多是简单的)实例化和设置,必须以特定的方式以特定的顺序完成.

但是,嘿,现在这是一个临时解决方法:在 MSVC2008 和 MSVC2010 编译器上确认(LNK1179每个错误相同,在应用解决方法后每个都成功链接)。

这是编译器和/或链接器错误,因为代码是“简单/正确的 C++”(甚至不是 C++11)。

所以,我很高兴(我在全职工作 2 周后得到了一个链接)。但是,很失望(编译器和/或链接器有一个愚蠢的问题,在这个用例中链接一个简单的模板<>,我无法弄清楚如何解决)

进一步,“赏金结束”,但没有其他人愿意接受这个(没有其他答案?),所以看起来“ +100 ”不给任何人。(沉重的叹息)

于 2012-11-21T14:16:08.480 回答
4

这个问题有很多答案,但没有一个能完全捕捉到我的代码库中发生的事情,以及我怀疑 OP 在 2012 年被问到这个问题时看到的内容。

问题

使用带有和属性的指令IID_*很容易意外重现类型上的 COMDAT 错误。#importrename_namespacenamed_guids

如果两个#imported 类型库包含相同的接口,就像 OP 的情况一样IXMLDOMImplementation,那么生成的.tlh文件将IID_IXMLDOMImplementation在两个命名空间中声明,从而导致重复。

例如,生成的代码:

#import <foo.tlb> rename_namespace("FOO") named_guids;
#import <bar.tlb> rename_namespace("BAR") named_guids;

...可以简化成这样的:

namespace FOO {
    extern "C" __declspec(selectany) const GUID IID_IFOOBAR = {0};
}

namespace BAR {
    extern "C" __declspec(selectany) const GUID IID_IFOOBAR = {0};
}

这是问题的简单 RexTester 重现:https ://rextester.com/OLAC10112

named_guids属性导致IID_*生成 并且该rename_namespace属性将其包装在名称空间中。

不幸的是,在这种情况下,extern "C"当它出现在 C++ 命名空间中时,它似乎没有按预期工作。IID_FOOBAR这会导致编译器在同一个.obj文件 中生成多个定义。DUMPBIN /SYMBOLS或十六进制编辑器确认重复的符号。

链接器看到这些多个定义并发出duplicate COMDAT诊断。

一个解法

知道这rename_namespace不能很好地与 一起使用named_guids,显而易见的解决方案是根本不将它们一起使用。删除该named_guids属性并改用_uuidof()operator可能是最简单的。

named_guids#import指令中删除并修改代码,替换所有使用FOO::IID_IFooBarwith_uuidof(FOO::IFooBar)之后,我的 COM 重代码库又重新开始构建了。

于 2018-10-22T18:45:51.163 回答
1

此问题在 Visual Studio 2017 的某些特定版本中报告为错误。尝试修补 15.9.1 或更高版本以修复此问题

于 2019-01-19T04:37:43.970 回答
0

我在将一些代码(1)从 MSVC 移植到 GCC 时遇到了这个问题。为了让构建链接到 GCC,我必须为一些专门的模板函数 (2) 提供空实现,这导致了 MSVC 上的 LNK1179。我能够通过内联函数(3)来解决,即

  1. template<> template<> void LongName1<LongName2>::FunctionName(boost::library::type1 & a, const unsigned int b);
  2. template<> template<> void LongName1<LongName2>::FunctionName(boost::library::type1 & a, const unsigned int b) {};
  3. template<> template<> inline void LongName1<LongName2>::FunctionName(boost::library::type1 & a, const unsigned int b) {};
于 2013-08-29T08:21:57.027 回答
0

我收到了这个错误,对此感到非常困惑。结束注释掉引用的 cpp 中的所有内容并小批量重新引入内容,直到文件恢复到与我开始时相同的状态。而且我不再收到错误消息。对我来说,这在我的情况下表明这是编译器中的一个错误,但由于我无法再重现它,所以我无法获得更多帮助。

我在:Microsoft Visual Studio Professional 2019 版本 16.11.3

于 2021-10-15T07:00:48.897 回答
0

希望我蹩脚的解决方法可以帮助某人:我确保手动删除所有 .obj 和中间构建文件(至少包括 .pch、.pdb、.tlog、.lastbuildstate 和其他任何看起来可疑的东西)并从头开始重建。

我建议在没有证据的情况下,从以前的构建中遗留一些文件往往会导致问题更频繁地发生。在我的特定构建系统中,我也从头开始删除并重新创建 .vcxproj 和 .sln 文件。

我个人的怀疑是,在读取中间文件的时间和在大型项目中写入它们的时间之间,构建/链接过程中存在某种竞争条件。同样,我没有证据证明这是真的,但这是我唯一的猜测,似乎符合该错误的所有已知事实。

于 2016-02-16T02:16:44.723 回答
0

I wrote Outlook addins years ago and I was asked to write another. Right off the bat, I ran into this problem and through a little process of elimination, I fixed mine.

It turns out that when you choose an extensibity project(I hand coded mine back in the day), it creates and save 2 objects that I was unaware of: DTE and DTE80. To create the interfaces that manipulate these objects, they import directly from the DLLs in stdafx.h. Being that I'm working on Outlook, I also needed to import a couple of interfaces: Office and Outlook.

So, seeing as this error popped up almost immediately after writing my first tidbits of code, I started over, and added one thing at a time. The project blew chunks in the described way right after I added:

//Added mvc 
//The following #import imports MSO based on it's LIBID
#import "libid:2DF8D04C-5BFA-101B-BDE5-00AA0044DE52" version("2.2") lcid("0") rename_namespace("Office") raw_interfaces_only named_guids
using namespace Office;

//The following #import imports Outoloks Object lib based on it's LIBID
#import "libid:00062FFF-0000-0000-C000-000000000046" rename_namespace("Outlook") raw_interfaces_only named_guids 
using namespace Outlook;

So, seeing as I had no intention of figuring out the DTE stuff, I just commented out them and anything having to do with them:

//The following #import imports VS Command Bars based on it's LIBID
//  #import "libid:1CBA492E-7263-47BB-87FE-639000619B15" version("8.0") lcid("0") raw_interfaces_only named_guids

//The following #import imports DTE based on it's LIBID
//  #import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version("8.0") lcid("0") raw_interfaces_only named_guids

//The following #import imports DTE80 based on it's LIBID
//  #import "libid:1A31287A-4D7D-413e-8E32-3B374931BD89" version("8.0") lcid("0") raw_interfaces_only named_guids

After wandering around fixing the compile errors, it compiled and linked just fine. I'm not suggesting this will work for everybody, but it worked for me. Good luck to any who pass by here....

于 2017-07-01T01:59:10.403 回答
0

我必须做 c++ -> 代码生成 -> 启用功能 - 级别链接 -> 否

于 2015-12-27T10:33:21.833 回答