“LNK2022:元数据操作失败” 让我发疯
我有一个包含很多项目的大型解决方案,使用 VS2008 SP1,并且每天至少遇到一次 LNK2022 错误。 如果我对解决方案进行完全重建,它会构建得很好,但这并不有趣。
当依赖 DLL 发生“轻微”更改(即不更改任何方法或类)并且稍后构建引用项目时,就会发生这种情况。 合并元数据时它会失败 - 无论这意味着什么。
首先要注意的是,共享 DLL 是通过多个 .CPP 文件中的 #using
引用的。
第二件事是,如果我从共享 DLL 中删除 AssemblyInfo.cpp 那么问题就会消失(但我不确定这是否是一个明智的解决方案?)。
我已将其范围尽可能缩小到以下解决方案,其中包含2 个 CLR 类库项目(xxx 项目依赖于 Shared):
以下是每个文件的内容:
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 ==========
编辑:
xxx.obj 和 xxx2.obj 的 IL 之间的差异如下:
(对于 xxx.obj)
// AssemblyRef #2 (23000002)
// ------------------------------------------------ --------
// 令牌:0x23000002
// 公钥或令牌:
// 名称:共享
// 版本:1.0.3412.16606
// 主要版本:0x00000001
// 次要版本:0x00000000
// 内部版本号:0x00000d54
// 修订号:0x000040de
// 区域设置:
// 哈希值 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.16585
// 主要版本:0x00000001
// 次要版本:0x00000000
// 内部版本号:0x00000d54
// 修订号:0x000040c9
// 区域设置:
// 哈希值 Blob:64 af d3 12 9d e3 f6 2b 59 ac ff e5 3b 38 f8 fc 6d f4 d8 b5
// Flags: [none] (00000000)
这对我来说意味着 xxx2.obj 仍在使用旧版本的 Shared.dll,并且与使用更新的 Shared.dll 的 xxx.obj 发生冲突。 那么我该如何解决这个问题呢?
I have a big solution with lots of projects, using VS2008 SP1, and at least once a day I encounter the LNK2022 error. If I do a full rebuild of the solution it builds fine, but this is not fun.
It happens when a dependent DLL is changed 'insignificantly' (i.e. without changing any methods or classes), and the referencing project is later built. It fails when merging the metadata - whatever that means.
First thing to note is that the shared DLL is referenced with #using
from multiple .CPP files.
Second thing is that if I delete the AssemblyInfo.cpp from the shared DLL then the problem goes away (but I'm not sure if this is a sensible fix?).
I've narrowed it down as far as possible into the following solution containing 2 CLR Class Library projects (the xxx project depends on Shared):
Here are the contents of each file:
Shared.cpp:
public ref class Shared
{
};
inc.h:
#pragma once
#using "Shared.dll"
public ref class Common
{
private:
Shared^ m_fred;
};
xxx.cpp and xxx2.cpp:
#include "inc.h"
To reproduce, first rebuild the solution. It will build OK.
Now save Shared.cpp and build the solution, it will build fine and show:
...
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 ==========
Now save xxx.cpp and build the solution, it fails with the following message:
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 ==========
EDIT:
The differences between the IL for xxx.obj and xxx2.obj are as follows:
(for xxx.obj)
// AssemblyRef #2 (23000002)
// -------------------------------------------------------
// Token: 0x23000002
// Public Key or Token:
// Name: Shared
// Version: 1.0.3412.16606
// Major Version: 0x00000001
// Minor Version: 0x00000000
// Build Number: 0x00000d54
// Revision Number: 0x000040de
// Locale:
// HashValue Blob: 1c bb 8f 13 7e ba 0a c7 26 c6 fc cb f9 ed 71 bf 5d ab b0 c0
// Flags: [none] (00000000)
(for xxx2.obj)
// AssemblyRef #2 (23000002)
// -------------------------------------------------------
// Token: 0x23000002
// Public Key or Token:
// Name: Shared
// Version: 1.0.3412.16585
// Major Version: 0x00000001
// Minor Version: 0x00000000
// Build Number: 0x00000d54
// Revision Number: 0x000040c9
// Locale:
// HashValue Blob: 64 af d3 12 9d e3 f6 2b 59 ac ff e5 3b 38 f8 fc 6d f4 d8 b5
// Flags: [none] (00000000)
This implies to me that xxx2.obj is still using the old version of Shared.dll, and that is conflicting with xxx.obj which is using the updated Shared.dll. So how can I workaround that then?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
此问题是由 Visual Studio 2008 中新的托管增量构建功能引起的。正如您所发现的,元数据确实发生了更改,但并未以托管增量构建功能认为重要的方式发生变化。 但是,如果您强制重新编译其中一个 cpp 文件,它会获取新的元数据,将其嵌入到 obj 中,然后链接器会发现冲突。
有两种方法可以解决这个问题。 一种似乎有效的简单方法,来自demoncodemonkey的回答如下 是在引用的程序集元数据中指定显式版本号,以指示编译器引用的程序集实际上处于同一版本:
避免此问题的另一种方法是禁用该功能。 我们可能会不必要地重新编译一些cpp文件,但这比链接器失败要好。
在项目属性中,在“配置属性”>下 常规,将“启用托管增量构建”设置为否。
This problem is caused by the new Managed Incremental Build feature in Visual Studio 2008. As you spotted, the metadata did change, but not in a way that the managed incremental build feature considers signifcant. However, if you force a recompile of one of the cpp files, it grabs the new metadata, embeds it in the obj, and then the linker sees a conflict.
There are two ways to resolve this problem. A simple way that seems to work, from demoncodemonkey's answer below is to specify an explicit version number in the referenced assembly metadata to instruct the compiler that the referenced assembly is in fact at the same version:
The alternative way to avoid this problem is by disabling the feature. We may recompile some cpp files unnecessarily, but it's better than having the linker fail.
In the project properties, under Configuration Properties > General, set "Enable Managed Incremental Build" to No.
微软回复了我的 Connect 帖子,提供了更好的解决方法:
这对我有用,显然这比禁用该功能更好。
无论如何,已选择接受的答案,现在无法更改:(编辑:我设法不接受我的答案并将尼克的答案标记为已接受的答案:)
Microsoft replied to my Connect post, with a much better workaround:
This works for me and obviously this is preferable to disabling the feature.
Anyway the accepted answer has been chosen and cannot be changed now :(Edit: I managed to unaccept my answer and mark Nick's answer as the accepted answer :)
在 xxx.cpp 和 xxx2.cpp 中尝试此操作:
在这种情况下,
#pragma Once
不足以保护标头。Try this in xxx.cpp and xxx2.cpp:
#pragma once
isn't enough to protect the header in this case.