【发布时间】:2020-08-06 17:57:58
【问题描述】:
简介:
托管 (/clr) C++ 项目 (.dll) 静态链接本机 C++ 库(使用 /MD 编译)。静态库很大,并且引用了许多其他库,但托管 C++ 代码使用的功能微不足道,不应引入任何额外的依赖项。
问题:
- 链接失败,
LNK2001和LNK2019提到代码绝对不依赖的符号 - 即使我添加了所需的依赖项,切换工具集(例如从
VS2017迁移到VS2019)也会导致错误再次出现(这次提到其他依赖项)
会发生什么:
显然,/clr 开关导致编译器以不同的方式处理内联函数——它们不再嵌入到.obj 文件中(作为“弱符号”),而是在导入表中被引用。这意味着链接器必须找到以下内容:
"public: virtual char const * __cdecl std::exception::what(void)const " (?what@exception@std@@UEBAPEBDXZ)
... 它所做的并且(因为 CRT 库是 DEFAULTLIB 并因此最后使用)通常它会在其他库中找到它(即在上述静态本机库中)。因此,它在包含std::exception::what() 的静态库中找到第一个.obj 文件并将其拉入——这意味着我们现在依赖于.obj 所依赖的所有内容。这解释了问题 #1(虚假链接器错误)。
现在,如果您使用另一个工具集编译您的静态库 -- obj 文件可能会以不同的顺序存储,从而导致问题 #2。
要重现该问题,您可以使用此代码(确保托管项目链接静态库):
//--------------------
// statlib.cpp
//
#include <exception>
void this_is_a_trap() { throw std::exception(); }
extern int bar();
int foo() { return bar(); }
//--------------------
// clrdll.cpp (managed code)
//
#include <exception>
__declspec(dllexport) void oops()
{
throw std::exception();
}
如果你链接 /VERBOSE 标志,你会看到类似:
1> Searching C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x64\oleaut32.lib:
1> Searching C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x64\uuid.lib:
1> Searching C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x64\odbc32.lib:
1> Searching C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x64\odbccp32.lib:
1> Searching C:\tst\x64\Release\statlib.lib:
1> Found "public: virtual char const * __cdecl std::exception::what(void)const " (?what@exception@std@@UEBAPEBDXZ)
1> Referenced in clrdll.obj
1> Loaded statlib.lib(statlib.obj) <-- Now we depend on `bar()`
问题
解决这个问题的最佳方法是什么?
注意事项:
-
将
msvcrt.lib添加到链接器输入(在其他静态库之前)会有所帮助,但并非总是如此——某些符号(例如std::bad_weak_ptr::what()在msvcrt.lib中不存在) -
这个问题是this SO post的根本原因
【问题讨论】:
标签: visual-c++ clr managed-c++