“LNK2022: operação de metadados falhou” me deixando louco
-
03-07-2019 - |
Pergunta
Eu tenho uma solução grande com lotes de projetos, usando VS2008 SP1, e pelo menos uma vez por dia eu encontrar o erro LNK2022. Se eu reconstruir um completo da solução que constrói bem, mas isso não é divertido.
Isso acontece quando uma DLL dependente é alterado 'insignificante' (ou seja, sem alterar quaisquer métodos ou classes), eo projeto de referência é construído mais tarde. Ele falha ao mesclar os metadados -. O que isso significa
A primeira coisa a notar é que a DLL compartilhada é referenciado com #using
de vários arquivos .CPP.
A segunda coisa é que, se eu apagar o AssemblyInfo.cpp do DLL compartilhada então o problema vai embora (mas eu sou não sei se isso é uma solução sensata? ).
Eu reduzi-lo o mais longe possível na href="http://www.2shared.com/file/5575794/7f03c4c4/xxx.html" rel="nofollow solução seguinte contendo 2 projetos de biblioteca de classes CLR (o xxx projeto depende de Shared ):
Eis o conteúdo de cada arquivo:
Shared.cpp:
public ref class Shared
{
};
inc.h:
#pragma once
#using "Shared.dll"
public ref class Common
{
private:
Shared^ m_fred;
};
xxx.cpp e xxx2.cpp:
#include "inc.h"
Para reproduzir, primeiro recriar a solução. Ele vai construir OK.
Agora salve Shared.cpp e construir a solução, ele vai construir bem e mostrar:
...
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 ==========
Agora salve xxx.cpp e construir a solução, ele falha com a seguinte mensagem:
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 ==========
Editar :
As diferenças entre a IL para xxx.obj e xxx2.obj são como se segue:
(para xxx.obj)
// AssemblyRef # 2 (23000002)
// ------------------------------------------------ -------
// token: 0x23000002
// chave pública ou Token:
// Nome:
Shared
// Versão: 1.0.3412.16 606
// Versão Major: 0x00000001
// versão menor: 0x00000000
// número de compilação: 0x00000d54
// Número de Revisão: 0x000040 de
// Locale:
// HashValue Blob: 1c bb 8F 13 7e ba 0a c7 26 c6 fc cb f9 ed 71 bf 5d ab b0 c0
// Flags: [nenhum] (00000000)
(para xxx2.obj)
// AssemblyRef # 2 (23000002)
// ------------------------------------------------ -------
// token: 0x23000002
// chave pública ou Token:
// Nome:
Shared
// Versão: 1.0.3412.16 585
// Versão Major: 0x00000001
// versão menor: 0x00000000
// número de compilação: 0x00000d54
// Número de Revisão: 0x000040 C9
// Locale:
// HashValue Blob: 64 af d3 12 9d e3 f6 2b 59 ac ff e5 3b 38 f8 fc 6d f4 d8 b5
// Flags: [nenhum] (00000000)
Isto implica para mim que xxx2.obj ainda está usando a versão antiga do Shared.dll, e que está em conflito com xxx.obj que está usando o Shared.dll atualizado. Então, como posso resolver isso então?
Solução 2
Microsoft respondeu ao meu post Connect, com uma melhor solução muito:
Parece que o problema é causado por a incompatibilidade na versão entre o dois .objs. Uma solução melhor é substitua
[montagem: AssemblyVersionAttribute ( "* 1.0")];
com
[montagem: AssemblyVersionAttribute ( "1.0.0.1")];
em AssemblyInfo.cpp. Isso irá garantir que a versão não muda entre compilações incrementais.
Isso funciona para mim e, obviamente, isso é preferível a desativação do recurso.
De qualquer forma a resposta aceita foi escolhido e não pode ser mudado agora: (
Outras dicas
Esse problema é causado pela nova gestão recurso de compilação incremental no Visual Studio 2008. Como você viu, os metadados se alterou, mas não de uma forma que o recurso de compilação incremental conseguiu considera signifcant. No entanto, se você forçar uma recompilação de um dos arquivos do CPP, que agarra o novo metadados, incorpora-lo no obj, e em seguida, o vinculador vê um conflito.
Existem duas formas para resolver este problema. Uma maneira simples que parece trabalho, de resposta abaixo é especificar um número de versão explícita na referenciado assembly metadados para instruir o compilador que a referência de montagem é de fato na mesma versão:
Substitua
[assembly:AssemblyVersionAttribute("1.0.*")];
com
[assembly:AssemblyVersionAttribute("1.0.0.1")];
em
AssemblyInfo.cpp.
Isso irá garantir que a versão não mudança entre compilações incrementais.
A maneira alternativa para evitar este problema é desativar o recurso. Podemos recompilar alguns arquivos CPP desnecessariamente, mas é melhor do que ter o vinculador falhar.
Nas propriedades do projeto, em Configuração de Propriedades> Geral, defina "Ativar Managed compilação incremental" para Não.
Tente isto em xxx.cpp e xxx2.cpp:
#ifndef _PROTECT_MY_HEADER
#define _PROTECT_MY_HEADER
#include "inc.h"
#endif
#pragma once
não é suficiente para proteger o cabeçalho neste caso.