“ LNK2022:メタデータ操作に失敗しました”私を狂わせる
-
03-07-2019 - |
質問
VS2008 SP1を使用して、多くのプロジェクトで大きなソリューションを使用していますが、少なくとも1日に1回、LNK2022エラーが発生します。ソリューションを完全に再構築すると問題なくビルドできますが、これは面白くありません。
依存するDLLが「わずかに」変更された場合(つまり、メソッドやクラスを変更せずに)、参照プロジェクトが後でビルドされた場合に発生します。メタデータをマージするときに失敗します-それが意味することは何でも。
最初に注意することは、共有DLLは複数の.CPPファイルから #using
で参照されることです。
2つ目は、共有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
//公開キーまたはトークン:
//名前:Shared
//バージョン: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
//公開キーまたはトークン:
//名前:Shared
//バージョン: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と競合していることを意味します。では、どうすればそれを回避できますか?
解決 2
MicrosoftはConnectの投稿に返信しましたが、次善策があります:
問題の原因は次のとおりです 間のバージョンの不一致 2つの.obj。より良い回避策は 置換
[assembly:AssemblyVersionAttribute(" 1.0。*")];
with
[assembly:AssemblyVersionAttribute(" 1.0.0.1")];
AssemblyInfo.cppの。これにより、 バージョンが変わらないこと 増分ビルド間。
これは私にとっては有効であり、明らかにこの機能を無効にするよりも望ましい方法です。
とにかく、受け入れられた回答が選択されており、現在変更することはできません:(
他のヒント
この問題は、Visual Studio 2008の新しいマネージドインクリメンタルビルド機能が原因で発生します。ご覧のように、メタデータは変更されましたが、マネージドインクリメンタルビルド機能が重要と考える方法ではありません。ただし、cppファイルの1つを強制的に再コンパイルすると、新しいメタデータが取得されてobjに埋め込まれ、リンカーは競合を検出します。
この問題を解決するには2つの方法があります。 下記のdemoncodemonkeyの回答は、参照先アセンブリが実際に同じバージョンであることをコンパイラに指示するために、参照先アセンブリメタデータで明示的なバージョン番号を指定することです。
交換
[assembly:AssemblyVersionAttribute("1.0.*")];
with
[assembly:AssemblyVersionAttribute("1.0.0.1")];
in
AssemblyInfo.cpp。
これにより、バージョンが インクリメンタルビルド間の変更。
この問題を回避する別の方法は、機能を無効にすることです。不必要にいくつかのcppファイルを再コンパイルすることもできますが、リンカが失敗するよりはましです。
プロジェクトプロパティの[設定プロパティ]>一般、「管理されたインクリメンタルビルドを有効にする」を設定します。いいえ。
xxx.cppおよびxxx2.cppでこれを試してください:
#ifndef _PROTECT_MY_HEADER
#define _PROTECT_MY_HEADER
#include "inc.h"
#endif
この場合、ヘッダーを保護するには #pragma once
では不十分です。