【问题标题】:Why are there so many libraries in MSVC and why do I have to recompile the code again为什么MSVC中有这么多库,为什么还要重新编译代码
【发布时间】:2010-12-29 21:23:37
【问题描述】:

在每个平台上都有给定库的不同版本:多线程、调试、动态等。

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

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

对于 C/C++ 程序员在 Windows 中讨论这些库问题的可靠文档,我真的很感激。

谢谢!

【问题讨论】:

  • Linux 需要按库名称链接 - MS 提供 /Mx 开关是为了方便。
  • 所以这仅仅是为了方便自动库名称解析?

标签: visual-c++


【解决方案1】:

编译器设置除了简单地更改一些宏定义之外几乎没有什么作用。它的 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_&lt;function name&gt;,这意味着,在 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 中重复符号的令人困惑的消息,他们必须使用忽略默认库标志绕过这些消息。

【讨论】:

    【解决方案2】:

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

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

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

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

    我不推荐这样做,但如果你有理由需要这样做,它可以在大多数情况下工作。

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

    【讨论】:

      【解决方案3】:

      所有选项都使用相同的头文件,但是它们都暗示不同的#define,这会影响头文件。所以需要重新编译。

      开关也链接到相应的库,但重新编译不是因为链接。

      See here 列出了您使用它们时定义的内容。

      【讨论】:

      • 是的,是的。但是您没有回答我的问题:是什么使得有必要在在编译时进行更改以链接到不同版本的库?现在让我们假设我想取消自动链接。我不能只编译代码并链接到可用的任何版本的库吗?或者另一种情况,我不能编译一些带有调试的代码,一些带有发布标志并将它们链接在一起吗?
      • 实际上它确实回答了您的问题。如果包含头文件,并且头文件声明了不同的定义,则必须重新编译源文件。
      猜你喜欢
      • 2012-12-28
      • 2019-11-15
      • 2012-05-28
      • 1970-01-01
      • 2010-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多