Подтвердить что ты не робот

"LNK2022: операция метаданных завершилась неудачно"

У меня есть большое решение с большим количеством проектов, используя VS2008 SP1, и по крайней мере один раз в день я сталкиваюсь с ошибкой LNK2022. Если я полностью перестрою решение, оно строит отлично, но это не весело.

Это происходит, когда зависимая DLL изменяется "незначительно" (т.е. без изменения каких-либо методов или классов), и последующий проект ссылки. Это не удается при слиянии метаданных - что бы это ни значило.

Прежде всего следует отметить, что общая DLL ссылается на #using из нескольких файлов .CPP.
Во-вторых, если я удалю AssemblyInfo.cpp из общей DLL, проблема исчезнет (но я не уверен, что это разумное решение?).

Я сузил его, насколько это возможно, в следующее решение, содержащее 2 проекта библиотеки классов CLR (xxx зависит от Общий):
alt text http://i42.tinypic.com/jg2vds.png

Вот содержимое каждого файла:

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 для 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
// Флаги: [none] (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
// Флаги: [none] (00000000)

Это означает, что xxx2.obj все еще использует старую версию Shared.dll, и это противоречит xxx.obj, который использует обновленную версию Shared.dll. Итак, как я могу это сделать?

4b9b3361

Ответ 1

Microsoft ответила на мой пост Connect, с гораздо лучшим обходом:

Похоже, что проблема вызвана несоответствие в версии между два .objs. Лучшим обходным решением является заменить

[сборка: AssemblyVersionAttribute ( "* 1.0" )];

с

[сборка: AssemblyVersionAttribute ( "1.0.0.1" )];

в AssemblyInfo.cpp. Это обеспечит что версия не меняется между инкрементными строками.

Это работает для меня, и, очевидно, это предпочтительнее отключить эту функцию.
В любом случае принятый ответ был выбран и не может быть изменен сейчас: (

Ответ 2

Эта проблема вызвана новой функцией Managed Incremental Build в Visual Studio 2008. Как вы заметили, метаданные изменились, но не так, что управляемая функция инкрементной сборки считает значимой. Однако, если вы принудительно перекомпилируете один из файлов cpp, он захватывает новые метаданные, вставляет его в obj, а затем компоновщик видит конфликт.

Существует два способа решения этой проблемы. Простой способ, который, кажется, работает, из demoncodemonkey answer ниже, заключается в том, чтобы указать явный номер версии в ссылочных метаданных сборки, чтобы проинструктировать компилятор о том, что ссылка на сборку фактически находится на ту же версию:

Заменить

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

с

[assembly:AssemblyVersionAttribute("1.0.0.1")];

in AssemblyInfo.cpp. Это гарантирует, что версия не изменение между инкрементными строками.

Альтернативный способ избежать этой проблемы - отключить эту функцию. Мы можем перекомпилировать некоторые файлы cpp без необходимости, но это лучше, чем отказ компоновщика.

В свойствах проекта в разделе "Свойства конфигурации" > "Общие" установите "Включить управляемый инкрементный сбор" на "Нет".

Ответ 3

Попробуйте это в xxx.cpp и xxx2.cpp:

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

#pragma once недостаточно для защиты заголовка в этом случае.