使用/ c和/ MD选项编译C文件,然后链接.lib文件

时间:2014-06-17 05:43:40

标签: c visual-c++ linker linker-flags cl

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

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

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

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

当我们仅编译而不是链接时,将/MDcl一起使用会有什么用?

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

    如果没有,那么link默认使用静态或动态链接吗? /MD给出的cl对此有效吗?

1 个答案:

答案 0 :(得分:2)

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

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

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

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

  

.libs都不是导入库

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

  

默认链接使用静态或动态链接

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