为什么MSVC中有这么多的库,为什么我必须重新编译代码呢?

时间:2009-12-24 19:34:22

标签: visual-c++

在每个平台中都有给定库的各种版本:多线程,调试,动态等。

如果我在这里错了,请纠正我,但在Linux中,一个对象可以链接到任何版本的库,不管它是如何编译的。例如,在编译时不需要使用任何特殊标志来指定链接最终是否是动态或静态版本的运行时库(澄清:我不是在谈论创建动态/静态库,我说的是链接到它们 - 所以-fPIC不适用。调试或优化版本的库也是如此。

为什么在MSVC中(Windows通常与其他编译器一样。是吗?)我需要每次重新编译代码才能链接到不同版本的库?我在谈论/ MD,/ MT,/ MTd,/ MDd等标志。代码实际上每次都使用不同的系统头。如果是这样,为什么?

我非常感谢任何针对C / C ++程序员在Windows中讨论这些库事务的可靠文档的指示。

谢谢!

3 个答案:

答案 0 :(得分:4)

除了简单地更改某些宏定义之外,编译器设置的功能很少。它的microsoft的c-runtime头文件根据所选的运行时改变它们的行为。

首先,头文件使用#pragma指令在目标文件中嵌入一个指令,指定要包含哪个.lib文件,选择以下之一:msvcrt.lib,msvcrtd.lib,libcmt.lib和mibcmtd.lib

指令看起来像这样

#ifdef <release dll runtime>
#pragma comment(lib,"msvcrt.lib")
#endif

接下来,它还修改了在所有c-rt函数上使用的宏定义,如果选择了dll运行时,则会添加__declspec(dllimport)指令。此指令的作用是将导入的符号从'_strcmp'更改为'__imp__strcmp'

dll导入库(msvcrt.lib和msvcrtd.lib)将它们的符号(链接器)导出为__imp_<function name>,这意味着,在Visual C ++世界中,一旦编译完代码链接到dll运行时你无法改变主意 - 它们不会链接到静态运行时。 当然,情况并非如此 - dll导入库实际上以两种方式导出其公共符号:使用和不使用__imp_前缀。 这意味着针对静态运行时构建的代码可以在以后加入到与dll或静态运行时的链接中。

如果要为其他使用者构建静态库,则应确保编译器设置包括:

  1. 静态库设置之一,以便.lib的使用者可以自己选择使用哪个c-runtime,并且
  2. 设置“Omit Default Library Name”(/ Zl)标志。这告诉编译器忽略#pragma comment(lib,...指令,因此obj文件和生成的lib不具有任何类型的隐式运行时依赖性。如果不这样做,那么选择不同运行时设置的lib用户将看到有关libc.lib和msvcrt.lib中重复符号的令人困惑的消息,他们必须使用ignore default libraries标记来绕过这些消息。

答案 1 :(得分:1)

使用这些编译器选项有两个效果。自动#define一个宏可以由头文件(和你自己的代码)使用来做不同的事情。这只会影响C运行时的一小部分,您可以检查标题以查看它是否在您的情况下发生。

另一件事是C ++编译器在您的目标文件中嵌入了一个注释,告诉链接器自动包含MSVC运行时的特定风格,无论您是否在链接时指定该库。

这对于小程序很方便,只需在命令提示符cl myprogram.cpp键入即可编译和链接,从而生成myprogram.exe。

您可以通过将/nodefaultlib传递给链接器来阻止c-runtime的注释风格的自动链接。然后指定一个不同的c-runtime风格。如果你小心不要依赖_MT和#{1}}的#defines,这将有效 _DLL(请记住,标准C标头也可能会查看这些标题。)

我不建议这样做,但如果您有理由需要这样做,可以在大多数情况下使其工作。

如果您想知道C标头文件的哪些部分的行为不同,您应该只在标头中搜索_MT_DLL并查看。

答案 2 :(得分:0)

所有选项都使用相同的头文件,但它们都意味着不同的#define会影响头文件。所以他们需要重新编译。

交换机还链接到相应的库,但重新编译不是因为链接。

See here查看使用每个内容时定义的内容列表。