"LNK2022:元数据操作失败"让我疯狂

dem*_*key 24 linker metadata c++-cli assemblyinfo visual-studio-2008

我有很多项目的大解决方案,使用VS2008 SP1,并且每天至少遇到一次LNK2022错误.如果我对解决方案进行全面重建,它可以很好地构建,但这并不好玩.

当依赖DLL"无意义地"更改时(即不更改任何方法或类),并且稍后构建引用项目时,就会发生这种情况.合并元数据时失败 - 无论这意味着什么.

首先要注意的是共享DLL是#using从多个.CPP文件引用的.
第二件事是,如果我从共享DLL中删除AssemblyInfo.cpp,那么问题就会消失(但我不确定这是否是一个合理的修复?).

我已尽可能地将其缩小到包含2个CLR类库项目的以下解决方案(xxx项目依赖于共享):
alt text http://i42.tinypic.com/jg2vds.png

以下是每个文件的内容:

Shared.cpp:

public ref class Shared
{
};
Run Code Online (Sandbox Code Playgroud)

英寸:

#pragma once
#using "Shared.dll"
public ref class Common
{
private:
    Shared^ m_fred;
};
Run Code Online (Sandbox Code Playgroud)

xxx.cpp和xxx2.cpp:

#include "inc.h"
Run Code Online (Sandbox Code Playgroud)

要重现,首先要重建解决方案.它会建立好.
现在保存Shared.cpp并构建解决方案,它将构建正常并显示:

...
2>------ Build started: Project: xxx, Configuration: Debug Win32 ------
2>Inspecting 'd:\xxx\xxx\Debug\Shared.dll' changes ...
2>No significant changes found in 'd:\xxx\xxx\Debug\Shared.dll'.
2>xxx - 0 error(s), 0 warning(s)
========== Build: 2 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
Run Code Online (Sandbox Code Playgroud)

现在保存xxx.cpp并构建解决方案,它失败并显示以下消息:

1>------ Build started: Project: xxx, Configuration: Debug Win32 ------
1>Compiling...
1>xxx.cpp
1>Linking...
1>xxx2.obj : error LNK2022: metadata operation failed (80131188) : Inconsistent field declarations in duplicated types (types: Common; fields: m_fred): (0x04000001).
1>LINK : fatal error LNK1255: link failed because of metadata errors
1>xxx - 2 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 1 up-to-date, 0 skipped ==========
Run Code Online (Sandbox Code Playgroud)

编辑:
IL for xxx.obj和xxx2.obj之间的差异如下:

(对于xxx.obj)
// AssemblyRef#2(23000002)
// ---------------------------------- ---------------------
//令牌:0x23000002
//公钥或令牌:
//名称:共享
//版本:1.0.3412.16 606
//主要版本:0x00000001
//次要版本:0x00000000
//内部版本号:0x00000d54
//版本号:0x000040 de
//区域设置:
// HashValue Blob: 1c bb 8f 13 7e ba 0a c7 26 c6 fc cb f9 ed 71 bf 5d ab b0 c0
//标志:[无](00000000)

(对于xxx2.obj)
// AssemblyRef#2(23000002)
// ---------------------------------- ---------------------
//令牌:0x23000002
//公钥或令牌:
//名称:共享
//版本:1.0.3412.16 585
//主要版本:0x00000001
//次要版本:0x00000000
//内部版本号:0x00000d54
//版本号:0x000040 c9
//区域设置:
// HashValue Blob: 64 af d3 12 9d e3 f6 2b 59 ac ff e5 3b 38 f8 fc 6d f4 d8 b5
//标志:[无](00000000)

这对我来说意味着xxx2.obj仍在使用旧版本的Shared.dll,这与使用更新的Shared.dll的xxx.obj冲突.那么我该如何解决呢?

Nic*_*ins 24

此问题是由Visual Studio 2008中的新托管增量构建功能引起的.正如您所发现的那样,元数据确实发生了变化,但不是托管增量构建功能认为有意义的方式.但是,如果强制重新编译其中一个cpp文件,它会抓取新元数据,将其嵌入到obj中,然后链接器会发现冲突.

有两种方法可以解决此问题.一个似乎有用的简单方法,从demoncodemonkey下面的答案是在引用的程序集元数据中指定一个显式版本号,以指示编译器引用的程序集实际上是在同一个版本:

更换

[assembly:AssemblyVersionAttribute("1.0.*")];
Run Code Online (Sandbox Code Playgroud)

[assembly:AssemblyVersionAttribute("1.0.0.1")];
Run Code Online (Sandbox Code Playgroud)

in AssemblyInfo.cpp.这将确保版本在增量构建之间不会更改.

避免此问题的另一种方法是禁用该功能.我们可能会不必要地重新编译一些cpp文件,但它比链接器失败更好.

在项目属性中的"配置属性">"常规"下,将"启用托管增量构建"设置为"否".


dem*_*key 11

微软回复了我的Connect帖子,有一个更好的解决方法:

看起来这个问题是由两个.objs之间的版本不匹配引起的.更好的解决方法是更换

[组件:AssemblyVersionAttribute( "1.0*")];

[组件:AssemblyVersionAttribute( "1.0.0.1")];

在AssemblyInfo.cpp中.这将确保版本不会在增量构建之间发生变化.

这对我有用,显然这比禁用该功能更可取.
无论如何,已接受的答案已被选中,现在无法更改:(