28

我有很多项目的大解决方案,使用 VS2008 SP1,并且每天至少遇到一次 LNK2022 错误。如果我完全重建解决方案,它构建得很好,但这并不有趣。

它发生在依赖 DLL 被“不显着”地改变(即没有改变任何方法或类),并且后来构建了引用项目时。合并元数据时失败 - 不管这意味着什么。

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

我已尽可能将其缩小为包含 2 个 CLR 类库项目的以下解决方案( xxx项目依赖于Shared):
替代文字

以下是每个文件的内容:

共享.cpp:

public ref class Shared
{
};

英寸:

#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 ==========

编辑
xxx.obj 和 xxx2.obj 的 IL 之间的区别如下:

(for 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)

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

4

3 回答 3

25

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

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

代替

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

[assembly:AssemblyVersionAttribute("1.0.0.1")];

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

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

在项目属性中,在 Configuration Properties > General 下,将“Enable Managed Incremental Build”设置为 No。

于 2009-05-05T20:02:13.170 回答
12

Microsoft 回复了我的 Connect 帖子,提供了更好的解决方法:

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

[程序集:AssemblyVersionAttribute("1.0.*")];

[程序集:AssemblyVersionAttribute("1.0.0.1")];

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

这对我有用,显然这比禁用该功能更可取。
无论如何,已选择接受的答案,现在无法更改:(
编辑:我设法不接受我的答案并将尼克的答案标记为接受的答案:)

于 2009-07-07T09:07:29.470 回答
1

在 xxx.cpp 和 xxx2.cpp 中试试这个:

#ifndef _PROTECT_MY_HEADER
#define _PROTECT_MY_HEADER
#include  "inc.h"
#endif

#pragma once在这种情况下不足以保护标题。

于 2009-05-01T10:07:53.117 回答