将静态本机库链接到托管C ++项目会在 [英] Linking static native library to managed C++ project pulls unused (and unexpected) dependencies in
问题描述
简介:
托管( / clr
)C ++项目( .dll
)静态链接本机C ++库(使用 / MD
编译)。静态库很大,并引用了许多其他库,但是托管C ++代码使用的功能微不足道,不应引入任何其他依赖项。
Managed (/clr
) C++ project (.dll
) statically links native C++ library (which is compiled with /MD
). Static library is big and references a lot of other libraries, but functionality used by managed C++ code is trivial and shouldn't pull in any additional dependencies.
问题:
- 由于
LNK2001
和LNK2019
提到代码绝对不依赖的符号 - 即使我添加了必需的依赖项,也要切换工具集(例如,从
VS2017
迁移到VS2019
)导致错误再次出现(这次提及其他依赖项)
- linking fails with
LNK2001
andLNK2019
mentioning symbols that code definitely does not depend on - even if I add required dependencies, switching toolset (e.g. migrating from
VS2017
toVS2019
) causes errors to come back (this time mentioning other dependencies)
会发生什么:
显然, / clr
开关使编译器对内联函数的处理方式有所不同-它们不再嵌入 .obj
文件(作为弱符号),而是在导入表中引用它们。这意味着链接器必须查找以下内容:
Apparently, /clr
switch causes compiler to treat inlined functions differently -- they are no longer get embedded into .obj
files (as "weak symbols"), instead they get referenced in the table of imports. This means linker has to find things like:
"public: virtual char const * __cdecl std::exception::what(void)const " (?what@exception@std@@UEBAPEBDXZ)
...这样做和(因为CRT库 DEFAULTLIB
,因此最后使用),通常会在其他库(即上述静态本地lib)中找到它。因此,它将在静态lib中找到第一个 .obj
文件,该文件包含 std :: exception :: what()
并提取它-意味着我们现在依赖于 .obj
依赖的所有内容。这说明了问题1(虚假的链接器错误)。
... which it does and (since CRT libraries are DEFAULTLIB
and therefore are used last) typically it finds it in other library (namely, in aforementioned static native lib). So, it finds first .obj
file in static lib that contains std::exception::what()
and pulls it in -- meaning we now depend on everything said .obj
depends. This explains problem #1 (bogus linker errors).
现在,如果您使用其他工具集( obj
文件)编译静态库,可以按不同的顺序存储,从而导致问题2。
Now, if you compile your static lib with another toolset -- obj
files can be stored in different order, causing problem #2.
要重现此问题,可以使用以下代码(确保托管项目链接为静态lib):
To reproduce the issue you can use this code (make sure managed project links static lib):
//--------------------
// 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
标志链接您会看到类似的东西:
If you link with /VERBOSE
flag you'll see smth like:
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()`
问题
处理此问题的最佳方法是什么?
What is the best way to deal with this?
注意:
-
将
msvcrt.lib
添加到链接器输入(在其他静态库之前)会有所帮助,但并非总是如此-某些符号(如std :: bad_weak_ptr :: what()
不存在于msvcrt.lib
中)
adding
msvcrt.lib
to linker inputs (before other static libs) helps, but not always -- certain symbols (such asstd::bad_weak_ptr::what()
aren't present inmsvcrt.lib
)
此问题是此SO帖子
推荐答案
使用混合代码( / clr
和本机代码) std :: exception :: what()
(和其他类似符号)执行内联,但是这些定义受托管(非本地)。通常这不是问题,但是本机代码通过 std :: exception
的vtable引用 native 定义。通常,将这种引用(一旦解析失败)重定向到托管定义(如上所述,生成的托管定义),但是在这种情况下-本地定义是在另一个对象(来自本地静态库的随机对象)中找到重定向插入,导致该对象被引用。
In mixed (/clr
and native) code std::exception::what()
(and other similar symbols) do get inlined, but these definitions are managed (not native). Which normally is not an issue, but native code refers to native definition via std::exception
's vtable. Normally, such reference (once it fails to resolve) gets redirected to managed definition (which is generated, as stated above), but in this case -- native definition is found in another object (random object from native static library) before "redirection" kicks in, causing that object to be referenced.
查看详细信息此处。 MS正在寻找解决此问题的最佳方法。
See details here. MS is figuring out a best way to deal with this.
这篇关于将静态本机库链接到托管C ++项目会在的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!