1

很抱歉接下来的长篇文章。

我知道混合使用 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?

谢谢你的耐心 :-)。

4

2 回答 2

3

我有我的问题的解决方案。大概是自古遗留下来的愚蠢错误吧。

我们在 Additional Dependencies 框中明确提到了 msvcrt.lib :-( 所以当然它使 dll 成为依赖项。而且由于所有开源库,该框有很多文本,所以我们没有注意到它。老实说,我们甚至没有考虑仔细查看那个盒子,因为我们没有想到我们的项目会出现如此严重的错误。

于 2009-10-15T07:23:40.640 回答
1

使用depends.exe 打开您的可执行文件并运行内置于depends 中的分析器。我相信这将记录为什么加载所有 dll 以及从何处加载它们。请参阅“记录 LoadLibrary 函数调用”选项。

于 2009-10-14T23:51:04.617 回答