将静态本机库链接到托管 C++ 项目会拉取未使用的(和意外的)依赖项

Linking static native library to managed C++ project pulls unused (and unexpected) dependencies in

剧情简介:

托管 (/clr) C++ 项目 (.dll) 静态 links 本机 C++ 库(使用 /MD 编译)。静态库很大并且引用了很多其他库,但是托管 C++ 代码使用的功能是微不足道的,不应该引入任何额外的依赖项。

问题:

  1. linking 失败,LNK2001LNK2019 提及代码绝对不依赖的符号
  2. 即使我添加了所需的依赖项,切换工具集(例如从 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()`

问题

处理这个问题的最佳方法是什么?

备注:

在混合(/clr 和本机)代码中 std::exception::what()(和其他类似符号)do 得到内联,但这些定义是 managed(非本机)。这通常不是问题,但本机代码通过 std::exception 的 vtable 引用 native 定义。通常,此类引用(一旦无法解析)将被重定向到托管定义(如上所述生成),但在这种情况下 - 在“重定向”之前在另一个对象(来自本机静态库的随机对象)中找到本机定义" 开始,导致该对象被引用。

查看详情here。 MS 正在寻找解决此问题的最佳方法。