为什么运行时库是编译器选项而不是链接器选项?

我正在尝试使用visual studio 2005构建一个C / C ++静态库。由于运行时库的选择是一个编译选项,我不得不构建我的库的四个变体,一个用于运行时库的每个变体:

  • / MT – 静态运行时库
  • / MD – DLL运行时库
  • / MTd – 调试静态运行时库
  • / MDd – 调试DLL运行时库

这些是编译器选项,而不是链接器选项。 来自Linux背景,这看起来很奇怪。 不同的运行时库是否有不同的调用约定? 为什么不能在链接时解析不同的运行时库,即当我链接使用我的静态库的应用程序时?

这些选项可能会添加运行时库头文件中使用的定义(例如__DLL和_​​_DEBUG)。 一个常见的事情是在动态链接时将__declspec(dllimport)添加到函数声明中。

编译器似乎也使用这些来帮助链接器链接到正确的库。 这在MSDN中进行了解释。

编译器需要知道您是否生成单线程或multithreading代码。 默认情况下,编译器生成线程安全代码(multithreading)。 如果你想要单线程代码,你必须告诉它。如果你更改默认值,编译器会更改默认的运行时库(你总是可以在链接器命令选项中覆盖它,只需确保你选择的库具有相同的代码结构作为您的目标文件:单线程静态,multithreading静态或multithreadingDLL)。 请注意,没有单线程DLL选项(根据定义,运行时库DLL将被构建为线程安全,因为它由多个应用程序共享)。

如果忽略静态运行时,则会获得与Linux相同的选项。

我知道静态运行时可能很有用,但我从来没有真正需要它。 此外,它会导致处理内存分配/释放的潜在问题,因此我发现只使用DLL运行时更容易。

发布/调试版本与Linux / Unix相同。
虽然为了效率,我认为我还构建了一个单线程和multithreading版本的库。

我相信这背后的原因是SEH(结构化exception处理程序)代码将根据您链接的运行时库的不同而生成。

为DLL和静态库生成了不同的机器代码。

在Linux上你必须这样做,如果你想构建一个共享库,编译器标志被称为-fPIC。 否则在AMD64和SPARC(以及其他人)上会崩溃。 在i386架构上,链接器非常聪明,不会在内存中共享库,因此不会崩溃。