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

时间:2009-05-01 09:52:37

标签: visual-studio-2008 linker c++-cli metadata assemblyinfo

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

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

首先要注意的是,共享DLL是使用来自多个.CPP文件的#using引用的 第二件事是,如果我从共享DLL中删除AssemblyInfo.cpp,那么问题就会消失(但我not sure if this is a sensible fix?)。

我已将其尽可能地缩小到包含2个CLR类库项目的以下solution中( xxx 项目取决于共享):
alt text

以下是每个文件的内容:

Shared.cpp:

public ref class Shared
{
};

inc.h:

#pragma once
#using "Shared.dll"
public ref class Common
{
private:
    Shared^ m_fred;
};

xxx.cpp和xxx2.cpp:

#include "inc.h"

要重现,请先重建解决方案。它会建立好。
现在保存 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 ==========

现在保存 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 ==========

修改
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冲突。那么我该如何解决呢?

3 个答案:

答案 0 :(得分:24)

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

有两种方法可以解决此问题。从demoncodemonkey's answer below开始,一种似乎有效的简单方法是在引用的程序集元数据中指定一个显式版本号,以指示编译器引用的程序集实际上是同一版本:

  

替换

[assembly:AssemblyVersionAttribute("1.0.*")];
     

[assembly:AssemblyVersionAttribute("1.0.0.1")];
     AssemblyInfo.cpp.中的

这将确保版本不会   增量构建之间的变化。

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

在项目属性中,在Configuration Properties>下。常规,将“启用托管增量构建”设置为否。

答案 1 :(得分:11)

Microsoft回复了我的Connect帖子,其中有一个更好的解决方法:

  

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

     

[组件:AssemblyVersionAttribute( “1.0 *”)];

     

     

[组件:AssemblyVersionAttribute( “1.0.0.1”)];

     在AssemblyInfo.cpp中

。这将确保   该版本不会改变   在增量构建之间。

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

答案 2 :(得分:1)

在xxx.cpp和xxx2.cpp中尝试:

#ifndef _PROTECT_MY_HEADER
#define _PROTECT_MY_HEADER
#include  "inc.h"
#endif
在这种情况下,

#pragma once不足以保护标头。