1

我有一个使用 3-4 个外部库的 C 文件。它是使用cl.exeand link.exe(MSVC) 构建的。

构建脚本显示生成exe的过程分为两个阶段-

  • 使用 '/c' 选项cl.exe来获取.o文件。还给出了一堆其他标志,但我关心的是/MD. MSDN 说:

使应用程序使用运行时库的特定于多线程和特定于 DLL 的版本。定义 _MT 和 _DLL 并使编译器将库名称 MSVCRT.lib 放入 .obj 文件中。

当我们只编译而不链接时,给予/MDwith 有什么用?cl

  • 在此之后,link.exe用于生成 exe。为链接指定了几个.lib文件(如 ole32.lib、advapi32.lib、user32.lib 等以及其他非 MSVC 特定的文件)。我的问题是不是.lib用于静态链接的文件吗?如果是,那么为什么最终的 exe 只有大约 500 KB?没有一个.lib是导入库。

    如果不是,那么link默认情况下使用静态链接还是动态链接?/MD给定的 withcl在这里有什么影响吗?

4

1 回答 1

3

从未设想过最初的 C 运行时库必须支持由多个模块构建的程序。它包含全局变量,如errnostdout,以及具有隐式全局状态的函数,如strtok()malloc()。您可以将 DLL 与其自己的 CRT 副本链接,但这对您如何设计 DLL 接口提出了相当严格的要求。您必须非常小心,不要依赖 CRT 状态。弄错这个错误几乎不可能诊断出运行时的不当行为。

解决此问题的方法是在您的流程中只拥有一份CRT 副本。这是 /MD 完成的任务,您最终将依赖于存储在 DLL 中的 CRT 版本。由所有模块共享。像msvcr120.dll,VS2013使用的那个。

编译器需要知道这一点,才能正确使用该 DLL 版本。一个简单的例子是errno,它是一个带有 /MT 的全局变量,但它被宏编辑为带有 /MD 的函数调用,因此只有 DLL 中的一个全局变量用于跟踪最后一个已知值。如果 /MD 生效,_DLL宏将被定义,在编译器的 .h 文件中使用。

另一个副作用是编译器会自动为 msvcrt.lib 或 libcmt.lib 插入链接指令(相当于#pragma 注释)。旨在帮助您避免错误并省略明确给出 CRT 库链接指令的需要。弄错会导致很难诊断链接器错误消息。与您尝试链接使用不匹配的 /MT 和 /MD 构建的 .obj 或 .lib 文件时得到的类型没有什么不同。哪个当然不能正常工作,你不能同时依赖两者。

.lib 都不是导入库

您按名称列出的 ole32.lib、advapi32.lib、user32.lib 实际上是导入库。它们是标准的操作系统 DLL。在运行时,您的程序将加载相应的 DLL,从调试器中很容易看到。对于 VS,您将在“输出”窗口中看到这一点。值得注意的是,这些 DLL 实际上使用的 CRT 与您的程序不同,它们绑定到 c:\windows\system32\msvcrt.dll。winapi 经过精心设计,绝不会成为问题。

链接默认使用静态链接还是动态链接

没有默认值,这取决于您链接的 .lib。区分静态链接库和导入库。构建 DLL 时会创建一个导入库。它是一个不包含代码的小文件,只有 DLL 中导出函数的名称,因此链接器知道在程序的导入表中放置一个条目。DLL依赖被解析,导入的函数在程序启动时被加载器绑定。

于 2014-06-17T10:54:59.243 回答