代码之家  ›  专栏  ›  技术社区  ›  demoncodemonkey

“lnk2022:元数据操作失败”让我精神错乱

  •  24
  • demoncodemonkey  · 技术社区  · 15 年前

    我有一个大的解决方案,有很多项目,使用VS2008 SP1,每天至少会遇到一次LNK2022错误。如果我做一个完整的重建解决方案,它建立良好,但这不是乐趣。

    当依赖的dll被“无意义地”更改(即不更改任何方法或类)并且引用项目随后被构建时,就会发生这种情况。它在合并元数据时失败——不管这意味着什么。

    首先要注意的是共享的dll被引用 #using 来自多个.cpp文件。
    第二件事是,如果我从共享的dll中删除assemblyinfo.cpp,那么问题就消失了(但我 not sure if this is a sensible fix? )

    我已经把范围缩小到以下几点 solution 包含2个clr类库项目 XXX 项目取决于 共享 ):
    alt text http://i42.tinypic.com/jg2vds.png

    以下是每个文件的内容:

    Shared.cpp:

    public ref class Shared
    {
    };
    

    公司:

    #pragma once
    #using "Shared.dll"
    public ref class Common
    {
    private:
        Shared^ m_fred;
    };
    

    xxx.cpp和xxx2.cpp:

    #include "inc.h"
    

    要复制,首先重建解决方案。它可以建造。
    现在保存 共享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)
    //组件参考2(23000002)
    /——————————————————————————————————————————————————————————————————————————————————————————————————————————————--
    //令牌:0x230000002
    //公钥或令牌:
    //名称:共享
    //版本:1.0.3412.16 六百零六
    //主版本:0x00000001
    //次要版本:0x00000000
    //内部版本号:0x00000D54
    //版本号:0x00040 判定元件
    / /场所:
    //哈希值blob: 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)
    /——————————————————————————————————————————————————————————————————————————————————————————————————————————————--
    //令牌:0x230000002
    //公钥或令牌:
    //名称:共享
    //版本:1.0.3412.16 五百八十五
    //主版本:0x00000001
    //次要版本:0x00000000
    //内部版本号:0x00000D54
    //版本号:0x00040 C9
    / /场所:
    //哈希值blob: 64 af d3 12 9d e3 f6 2b 59 ac ff e5 3b 38 f8 fc 6d f4 d8 b5
    //标志:【无】(00000000)

    这对我来说意味着x2.obj仍在使用旧版本的shared.dll,这与使用更新的shared.dll的xxx.obj冲突。那我该怎么解决呢?

    3 回复  |  直到 14 年前
        1
  •  24
  •   Community CDub    7 年前

    此问题是由Visual Studio 2008中新的托管增量生成功能引起的。正如您所看到的,元数据确实发生了变化,但并不是以管理增量构建特性认为有意义的方式。但是,如果强制重新编译其中一个cpp文件,它会获取新的元数据,将其嵌入到obj中,然后链接器会看到冲突。

    有两种方法可以解决这个问题。一种简单的方法,从 demoncodemonkey's answer below 在引用的程序集元数据中指定显式版本号,以指示编译器引用的程序集实际上处于同一版本:

    替换

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

    具有

    [assembly:AssemblyVersionAttribute("1.0.0.1")];
    

    在里面 AssemblyInfo.cpp. 这将确保该版本不会 在增量生成之间进行更改。

    避免此问题的另一种方法是禁用该功能。我们可以不必要地重新编译一些cpp文件,但这比链接器失败要好。

    在“项目属性”中的“配置属性”下,将“启用托管增量生成”设置为“否”。

        2
  •  11
  •   demoncodemonkey    15 年前

    微软回复了我的Connect帖子,提供了一个更好的解决方法:

    看来问题是由 版本不匹配 二、反对。更好的解决方法是 代替

    [程序集:assemblyversionattribute(“1.0.*”)];

    具有

    [程序集:assemblyversionattribute(“1.0.0.1”)];

    在assemblyinfo.cpp中。这将确保 版本不变 在增量生成之间。

    这对我很有效,显然这比禁用该功能更好。
    总之,已选择接受的答案,现在无法更改:(

        3
  •  1
  •   Steven Richards    15 年前

    在xxx.cpp和xxx2.cpp中尝试此操作:

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

    #pragma once 在这种情况下,不足以保护头。