将静态本机库链接到托管 C++ 项目会拉取未使用的(和意外的)依赖项
Linking static native library to managed C++ project pulls unused (and unexpected) dependencies in
剧情简介:
托管 (/clr
) C++ 项目 (.dll
) 静态 links 本机 C++ 库(使用 /MD
编译)。静态库很大并且引用了很多其他库,但是托管 C++ 代码使用的功能是微不足道的,不应该引入任何额外的依赖项。
问题:
- linking 失败,
LNK2001
和 LNK2019
提及代码绝对不依赖的符号
- 即使我添加了所需的依赖项,切换工具集(例如从
VS2017
迁移到 VS2019
)也会导致错误返回(这次提到其他依赖项)
发生了什么:
显然,/clr
开关导致编译器以不同方式处理内联函数——它们不再嵌入到 .obj
文件中(作为“弱符号”),而是在 table 的进口。这意味着 linker 必须找到类似的东西:
"public: virtual char const * __cdecl std::exception::what(void)const " (?what@exception@std@@UEBAPEBDXZ)
... 它确实如此并且(因为 CRT 库是 DEFAULTLIB
因此最后使用)通常它会在其他库中找到它(即在上述静态本机库中)。因此,它在包含 std::exception::what()
的静态库中找到第一个 .obj
文件并将其拉入——这意味着我们现在依赖于 .obj
所依赖的一切。这解释了问题 #1(伪造的 linker 错误)。
现在,如果您使用另一个工具集编译您的静态库 -- obj
文件可以以不同的顺序存储,导致问题 #2。
要重现问题,您可以使用此代码(确保托管项目 links 静态库):
//--------------------
// 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();
}
如果你 link 带有 /VERBOSE
标志,你会看到如下内容:
1> Searching C:\Program Files (x86)\Windows Kits\lib.0.17763.0\um\x64\oleaut32.lib:
1> Searching C:\Program Files (x86)\Windows Kits\lib.0.17763.0\um\x64\uuid.lib:
1> Searching C:\Program Files (x86)\Windows Kits\lib.0.17763.0\um\x64\odbc32.lib:
1> Searching C:\Program Files (x86)\Windows Kits\lib.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
添加到 linker 输入(在其他静态库之前)有帮助,但并非总是如此——某些符号(例如 std::bad_weak_ptr::what()
不是出现在 msvcrt.lib
)
这个问题是
的根本原因
在混合(/clr
和本机)代码中 std::exception::what()
(和其他类似符号)do 得到内联,但这些定义是 managed(非本机)。这通常不是问题,但本机代码通过 std::exception
的 vtable 引用 native 定义。通常,此类引用(一旦无法解析)将被重定向到托管定义(如上所述生成),但在这种情况下 - 在“重定向”之前在另一个对象(来自本机静态库的随机对象)中找到本机定义" 开始,导致该对象被引用。
查看详情here。 MS 正在寻找解决此问题的最佳方法。
剧情简介:
托管 (/clr
) C++ 项目 (.dll
) 静态 links 本机 C++ 库(使用 /MD
编译)。静态库很大并且引用了很多其他库,但是托管 C++ 代码使用的功能是微不足道的,不应该引入任何额外的依赖项。
问题:
- linking 失败,
LNK2001
和LNK2019
提及代码绝对不依赖的符号 - 即使我添加了所需的依赖项,切换工具集(例如从
VS2017
迁移到VS2019
)也会导致错误返回(这次提到其他依赖项)
发生了什么:
显然,/clr
开关导致编译器以不同方式处理内联函数——它们不再嵌入到 .obj
文件中(作为“弱符号”),而是在 table 的进口。这意味着 linker 必须找到类似的东西:
"public: virtual char const * __cdecl std::exception::what(void)const " (?what@exception@std@@UEBAPEBDXZ)
... 它确实如此并且(因为 CRT 库是 DEFAULTLIB
因此最后使用)通常它会在其他库中找到它(即在上述静态本机库中)。因此,它在包含 std::exception::what()
的静态库中找到第一个 .obj
文件并将其拉入——这意味着我们现在依赖于 .obj
所依赖的一切。这解释了问题 #1(伪造的 linker 错误)。
现在,如果您使用另一个工具集编译您的静态库 -- obj
文件可以以不同的顺序存储,导致问题 #2。
要重现问题,您可以使用此代码(确保托管项目 links 静态库):
//--------------------
// 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();
}
如果你 link 带有 /VERBOSE
标志,你会看到如下内容:
1> Searching C:\Program Files (x86)\Windows Kits\lib.0.17763.0\um\x64\oleaut32.lib:
1> Searching C:\Program Files (x86)\Windows Kits\lib.0.17763.0\um\x64\uuid.lib:
1> Searching C:\Program Files (x86)\Windows Kits\lib.0.17763.0\um\x64\odbc32.lib:
1> Searching C:\Program Files (x86)\Windows Kits\lib.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
添加到 linker 输入(在其他静态库之前)有帮助,但并非总是如此——某些符号(例如std::bad_weak_ptr::what()
不是出现在msvcrt.lib
)这个问题是
的根本原因
在混合(/clr
和本机)代码中 std::exception::what()
(和其他类似符号)do 得到内联,但这些定义是 managed(非本机)。这通常不是问题,但本机代码通过 std::exception
的 vtable 引用 native 定义。通常,此类引用(一旦无法解析)将被重定向到托管定义(如上所述生成),但在这种情况下 - 在“重定向”之前在另一个对象(来自本机静态库的随机对象)中找到本机定义" 开始,导致该对象被引用。
查看详情here。 MS 正在寻找解决此问题的最佳方法。