«LNK2022: операция с метаданными не удалась», сводя меня с ума - PullRequest
24 голосов
/ 01 мая 2009

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

Это происходит, когда зависимая DLL изменяется «незначительно» (т. Е. Без изменения каких-либо методов или классов), а ссылочный проект создается позже. Сбой при объединении метаданных - что бы это ни значило.

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

Я максимально сузил его до следующего решения , содержащего 2 проекта библиотеки классов CLR (проект xxx зависит от Shared ):
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 ==========

EDIT
Различия между IL для xxx.obj и xxx2.obj заключаются в следующем:

(для 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, и это конфликтует с xxx.obj, использующим обновленный Shared.dll. Так как я могу обойти это тогда?

Ответы [ 3 ]

24 голосов
/ 06 мая 2009

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

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

Заменить

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

с

[assembly:AssemblyVersionAttribute("1.0.0.1")];

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

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

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

.
11 голосов
/ 07 июля 2009

Microsoft ответила на мой пост о подключении с гораздо лучшим решением:

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

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

с

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

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

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

1 голос
/ 01 мая 2009

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

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

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

...