很抱歉接下来的长篇文章。
我知道混合使用 Microsoft 提供的静态链接和动态链接的 C 和 C++ 运行时并不是一个好主意。不幸的是,我们在工作中的应用程序已经将它们混合在一起,我们一直在努力解决这个问题。由于各种原因(其中不熟悉 MSI,我们使用的 NSIS 可能不能很好地支持 MSM,缺乏时间和资源),我们决定静态链接 CRT 而不是动态链接。我知道这不是一个好主意的原因,但这是我们现在的选择。
我们的代码主要是标准 C++,并辅以大量其他开源库。
应用程序的结构是:产生静态库的各种模块,它们本身链接在一起以创建各种东西,其中一个可执行文件给我们带来了问题。
在 Release 中,我们使用 /MT 构建所有代码。对于一些开源库,我们使用了预编译的二进制文件,其中一些是使用 /MD 预编译的 dll,这使我们混合了运行时。所以我们自己用 /MT 重新编译了它们,并让它们生成静态库而不是 dll。这种转换不是针对每个库都完成的,所以我们仍然链接一些使用 /MD 的 dll。
现在的结果是,在depends.exe 中,除了一个可执行文件之外,我们所有的东西都不直接依赖于msvcr80.dll 或msvcp80.dll。不直接依赖是指msvcr80.dll不是depends.exe 显示的树根的子级。有时我们确实发现 msvcr80.dll 被其中一个库 dll 拉入,但那是树中更深的一些级别。
我如何找出为什么 msvcr80.dll 在那个讨厌的可执行文件的第一级?是什么使该可执行链接直接指向 msvcr80.dll?
一个原因可能是我们静态链接到使用 /MD 链接的库 A,因此它与 CRT 动态链接。所以库 A 中的代码最终在我们的可执行文件中,因此我们的可执行文件与 msvcr80.dll 链接。但是我如何找出哪个库做到了这一点?
到目前为止我尝试了什么:
- 在depends.exe中加载静态链接的.lib文件->不起作用,因为depends.exe需要可执行文件或dll而不是静态库
- 在静态链接的 .lib 文件上使用 dumpbin.exe /DIRECTIVES -> 它们都没有显示 msvcrt80.dll (在调试中,我们尝试将 /MDd 用于所有内容,但它们确实显示了 msvcrt80d.dll,这让我认为方法是很好,它证明所有静态链接的开源库都用 /MT 正确编译)
- 使用 /VERBOSE:LIB 链接器标志 -> 它表明它确实在引入 msvcrt.lib,这是 msvcr80.dll 的导入库,所以我们遇到了麻烦,但它没有说明它为什么这样做
- 在 Visual Studio 中使用 /VERBOSE 链接器标志 +:附加依赖项 libcmt.lib + 忽略所有默认库 YES + 忽略特定库:msvcrt.lib 拼命尝试让 msvcrt.lib 消失或看看是谁拉了它。结果把我难住了:
搜索 C:\Program Files\Microsoft Visual Studio 8\VC\lib\msvcrt.lib: 找到“public: virtual void * __thiscall type_info::`向量删除析构函数'(unsigned int)”(??_Etype_info@@UAEPAXI@Z) 在 libcmt.lib(typinfo.obj) 中引用 加载 msvcrt.lib(ti_inst.obj) msvcrt.lib(ti_inst.obj) : error LNK2005: "private: __thiscall type_info::type_info(class type_info const &)" (??0type_info@@AAE@ABV0@@Z) 已经在 libcmt.lib(typinfo.obj) 中定义) msvcrt.lib(ti_inst.obj) : error LNK2005: "private: class type_info & __thiscall type_info::operator=(class type_info const &)" (??4type_info@@AAEAAV0@ABV0@@Z) 已在 libcmt.lib 中定义(typinfo.obj) 找到“void __stdcall `eh vector destructor iterator'(void *,unsigned int,int,void (__thiscall*)(void *))” (??_M@YGXPAXIHP6EX0@Z@Z) 在 msvcrt.lib(ti_inst.obj) 中引用 加载 msvcrt.lib(ehvecdtr.obj)
据我了解,libcmt.lib 中的 typinfo.obj 引用了一个符号,在 msvcrt.lib 中搜索它,然后在 ti_inst.obj 中找到它会引发一个错误,它被定义了两次。但这没有意义。如果 libcmt.lib 已经有符号,为什么它最终会在 msvcrt.lib 中搜索它并因此将 msvcr80.dll 带入我的可执行文件中?更一般地说,为什么静态库要在动态导入库中搜索符号?如果我在 Ignore 特定库中有链接器,为什么还要查看 msvcrt.lib?
谢谢你的耐心 :-)。