Вопрос

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

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

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

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

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

(для xxx.obj)
// Ссылка на сборку #2 (23000002)
// -------------------------------------------------------
// Токен:0x23000002
// Открытый ключ или токен:
// Имя:Общий доступ
// Версия:1.0.3412.16606
// Основная версия:0x00000001
// Второстепенная версия:0x00000000
// Номер сборки:0x00000d54
// Номер редакции:0x000040de
// Локаль:
// Большой двоичный объект с хэш-значением: 1c bb 8f 13 7e ba 0a c7 26 c6 fc cb f9 ed 71 bf 5d ab b0 c0
// Флаги:[нет] (00000000)

(для xxx2.obj)
// Ссылка на сборку #2 (23000002)
// -------------------------------------------------------
// Токен:0x23000002
// Открытый ключ или токен:
// Имя:Общий доступ
// Версия:1.0.3412.16585
// Основная версия:0x00000001
// Второстепенная версия:0x00000000
// Номер сборки:0x00000d54
// Номер редакции:0x000040с9
// Локаль:
// Большой двоичный объект с хэш-значением: 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.Итак, как я могу это обойти?

Это было полезно?

Решение 2

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

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

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

с

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

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

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

Другие советы

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

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

Заменить

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

с

[assembly:AssemblyVersionAttribute("1.0.0.1")];

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top