编译调试模式时出现错误:C++/CLI - 错误 LNK2022

3
我有一个包装了C++ DLL的CLI代码。
当我尝试以调试模式编译它时,会出现以下错误:

错误 22 错误 LNK2022: 元数据操作失败 (8013118D) :

重复类型的不一致布局信息.... MSVCMRTD.lib(locale0_implib.obj)

奇怪的是,在发布模式下,它可以正常编译和工作。
唯一的区别是我更改了以下内容:

配置属性 -> C/C++ -> 代码生成 -> 运行库

当设置为:多线程调试DLL (/MDd)时,会抛出错误。
当设置为:多线程DLL (/MD)时,可以正常编译。
所有其他项目中的DLL(CLI和C++)都使用相同的属性,也可以正常工作。
我正在使用VS2010。
那么,我该如何解决这个问题?
并且,我能否得到一些关于为什么会发生这种情况的解释?
更新:
我已经尝试更改项目属性中的每个选项,但没有运气。
我在某个地方读到,这可能是由于具有相同名称的类型的重复声明引起的。
但是在CLI文件中,我明确从std调用std::string等。
重命名对象无效。
还有其他想法吗?
更新:
一些错误复制粘贴:
error LNK2022: metadata operation failed (8013118D) : Inconsistent layout information in duplicated types (std._String_val<char,std::allocator<char> >): (0x02000097).  E:\MyProject....\MSVCMRTD.lib(locale0_implib.obj)   DllName


error LNK2022: metadata operation failed (8013118D) : Inconsistent layout information in duplicated types (std._String_iterator<char,std::char_traits<char>,std::allocator<char> >): (0x02000091).  E:\MyProject....\MSVCMRTD.lib(locale0_implib.obj)   AnotherDllName

请注意,MSVCMRTD.lib 文件实际上是用于编译的 MS 文件,不在我的项目中(也不应该在其中)。 更新: 如果这有帮助的话,这是链接器命令行:

/OUT:"E:\blah.CLI.dll" /INCREMENTAL /NOLOGO /LIBPATH:"e:\blah\Output\" /LIBPATH:"E:\blah\lib_64" /LIBPATH:"blah\Lib_64\" /DLL "e:\Otheblaf.lib" /MANIFEST /ManifestFile:"x64\Debug\blah.CLI.dll.intermediate.manifest" /ALLOWISOLATION /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"E:\blah.CLI.pdb" /SUBSYSTEM:WINDOWS /OPT:NOREF /OPT:NOICF /PGD:"E:\blah.CLI.pgd" /TLBID:1 /DYNAMICBASE:NO /FIXED:NO /MACHINE:X64 /ERRORREPORT:QUEUE

而下面这个可以工作的版本是:

/OUT:"E:\blah.CLI.dll" /INCREMENTAL:NO /NOLOGO /LIBPATH:"E:\blah\" /LIBPATH:"E:\blah\Output\" /LIBPATH:"E:\blah\lib_64" /DLL "Configuration.lib" "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" "E:\blah.lib" /MANIFEST /ManifestFile:"blah.CLI.dll.intermediate.manifest" /ALLOWISOLATION /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"E:\blah.CLI.pdb" /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /PGD:"E:\blah.CLI.pgd" /LTCG /TLBID:1 /DYNAMICBASE /FIXED:NO /MACHINE:X64 /ERRORREPORT:QUEUE


3
你已经问过完全相同的问题了。你肯定自那时以来已经发现了其他的东西吧? - Hans Passant
没有任何答案,我想重新提出这个问题。我还没有找到解决方案。(“只需使用/MD即可编译”)不是一个答案。 - Yochai Timmer
我已经尝试过移除“增量构建”...但没有起作用。谢谢。 - Yochai Timmer
我已经尝试过重命名类(使用重构很容易),但没有帮助。我回到办公室时会添加链接器命令行。 - Yochai Timmer
1
这里有另一个关于几乎相同问题的SO帖子:https://dev59.com/RG865IYBdhLWcg3wQMMD,也许那里的答案能帮到你。 - Doc Brown
显示剩余2条评论
6个回答

2
你是否在构建项目时使用自定义的make文件或自定义的编译器参数?这可能会以无法想象的方式影响项目。
[a] 可能是在构建该DLL时,#pragma pack设置为自定义编译器设置,导致Windows标准头文件中的结构体被错误地打包,从而导致大小不匹配。很容易解决...检查cl.exe的-Zp设置即可。这种情况可能解决结构体或类之一为您自己的自定义结构体或类的情况。

http://msdn.microsoft.com/en-us/library/xh3e3fd0%28v=VS.71%29.aspx

另一种可能出现这种情况的情况是当其中一个头文件包含Windows标准头文件并且#pragma pack没有被恢复时。这会将不正确的打包信息传播到标准头文件,导致与上述相同的问题。通常可以通过首先包含所有(虽然过于简化)Windows头文件来解决问题,以便稍后跳过它们。

希望这可以帮助你。


在我的一个CLI项目中,将标准的Windows std头文件包含到有问题的CLI头文件中确实起作用了。 - Yochai Timmer
我在使用CLR项目中的C++ libjson时遇到了完全相同的问题。禁用JSON_LESS_MEMORY(它设置了#pragma pack)解决了这个问题。谢谢! - A. Wilcox

1

终于找到了解决方案:

最后发现问题出在boost::lexical_cast<std:string>上。

使用某些std::对象时,.Net对象存在一个bug。(在我的情况下是std::string,正如错误信息所示)。

这是因为当他们创建这个框架时,他们重新发明了一些类(其中之一就是std::string),但在调试版本中没有正确地实现它。
该类的签名有点不同。

MSDN相关文章 - Ambiguous References

因此,解决方案是将有缺陷的类从.NET对象中“隐藏”。

创建一个C++级别的包装器类,将原始类的函数进行包装,并将有缺陷的类类型转换为编译正确的其他类类型。

确保包装类的头文件中没有对有缺陷的类类型的引用或包含。(可以通过仔细的前向引用/声明来完成)
使用VS2010,您可以明确编译未管理的包装器.cpp文件,而无需/clr。

然后,您可以正确地使用托管ref类与包装器类。

另一个选项

lexical_cast<std::string>替换为:

ostringstream os;
os << i;
return os.str();

0
当我将我的项目转换为64位时,出现了链接错误。我的解决方法是配置属性 > C/C++ > 代码生成 > 结构成员对齐 > 16字节 (/Zp16)

原帖已在其他地方找到了解决方案。 这对问题的理解有何帮助?它如何与给出的解决方案配合使用?当您重新开启一次讨论时,应提供理由和对比。 - Prune
这很危险。您正在更改项目中所有结构的对齐方式。这意味着任何链接到该项目的其他项目都需要以相同的方式进行编译。这将非常限制性。 - Yochai Timmer

-1

在编译调试模式之前,请确保清理构建。


-1

希望这个链接对你有所帮助。 在MSDN中建议运行“ildasm -tokens”命令来查找哪些类型在error_message中列出了标记,并寻找差异。

这里提供了一些关于ildasm exe的输入。


-1

我发现我项目中使用的WINVER与我链接的库中使用的不同。同步这些常量对我解决了问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接