我该使用/MD还是/MT编译?

152

在 Visual Studio 中,有编译标志 /MD 和 /MT 可供选择,用以选择要使用的 C 运行时库。

我了解它们的实现差异,但仍不确定应该使用哪个。它们各自的优缺点是什么?

我听说 /MD 的一个优点是,这可以让别人更新运行时库(比如可能修补安全问题),而我的应用程序也会受益于此更新。尽管对我来说,这似乎几乎不算一项功能:我不希望别人更改我的运行时库,而不允许我针对新版本进行测试!

以下是我想知道的一些事情:

  • 这会影响构建时间吗?(/MT 可能会稍微慢一些?)
  • 还有什么其他影响吗?
  • 大多数人都使用哪一个?

1
更多信息和建议可以在以下网址找到:https://dev59.com/m3RA5IYBdhLWcg3w6SNH - Weidenrinde
7个回答

101

通过与 /MD 动态链接,

  • 你会受到系统更新(无论好坏),
  • 你的可执行文件可以更小(因为它不包含嵌入式的库),并且
  • 我认为至少 DLL 的代码段在所有正在使用它的进程之间共享(减少了消耗的总 RAM 量)。

实际上,当与以不同运行时选项构建的静态链接第三方二进制库一起使用时,我发现主应用程序中的 /MT 往往比 /MD 更容易引起冲突(因为如果多次静态链接 C 运行时,尤其是不同版本,则会遇到麻烦)。


11
SxS 有些减少了系统更新的比特。EXE 程序可以声明其所需的 CRT 版本(是“需求”而非“获得”,因为安全更新可能会覆盖此设置)。 - MSalters
1
这是否意味着如果我使用MD编译,而我的程序依赖于某些dll,那么如果在一个不存在依赖dll的计算机上运行该程序,它将会失败? - gerrytan
5
@gerrytan:是的,你需要确保所有想运行软件的计算机上都有所需的DLL。通常的解决方案是让用户安装适当的MSVC可再发行程序包,或使用一个可以处理所有工作的安装程序。 - Mr Fooz
@Royi 我不确定,但我认为/MT在运行时会稍微快一些,因为您的应用程序不需要每次搜索运行时函数的实现。在这个水平上我不是专家,但我非常确定大多数操作系统将缓存运行时实现,所以你的应用程序将使用缓存版本,因此差异不会太大。请注意,我提到我不确定,所以不要把这个评论当成争论。 - Ahmed Kamal

46

如果你正在使用DLL,则应该选择动态链接的CRT(/MD)。

如果你为你的.exe和所有.dll使用动态CRT,那么它们将共享一个CRT实现 - 这意味着它们将共享一个CRT堆,一个.exe / .dll中分配的内存可以在另一个模块中被释放。

如果你为你的.exe和所有.dll使用静态CRT,那么它们将各自获得CRT的一个独立副本 - 这意味着它们将使用自己的CRT堆,因此必须在分配内存的同一模块中释放内存。你还将遭受代码膨胀(多个CRT的副本)和过多的运行时开销(每个堆从操作系统中分配内存来跟踪其状态,开销可能很明显)。


28

我认为通过Visual Studio构建的项目默认选项是/MD。

如果您使用/MT,则您的可执行文件不会依赖于目标系统上存在DLL。如果您将其包装在安装程序中,这可能不是问题,您可以选择任何一种方式。

我自己使用/MT,这样我就可以忽略整个DLL混乱。

另外,正如Fooz先生所指出的那样,保持一致非常重要。如果您链接其他库,您需要使用相同的选项。如果您使用第三方DLL,则几乎肯定需要使用运行时库的DLL版本。


18

我更喜欢使用静态链接,选择 /MT 选项。

虽然使用 /MD 选项可以得到更小的可执行文件,但是为了确保用户能够正确运行您的程序,您仍然需要发布一堆 DLL 文件。最终,您的安装程序会比使用 /MT 选项时还要大。

更糟糕的是,如果您选择将运行库放在 Windows 目录中,迟早会有用户安装一个带有不同运行库的新应用程序,并且运气不好的话,可能会破坏您的应用程序。


7
将"运行时库放在Windows目录中"是一个非常糟糕的想法。这样做会破坏其他在你之前也采取了相同方法的低级应用程序。请使用SxS并让安装程序处理,或者坚持使用/MT。 - MSalters
1
我完全同意这是一个不好的想法。虽然有些人会这样做,但我正在描述为什么这不是一个好主意。 - Adrian Grigore
5
不完全正确。在您的应用程序上安装其他应用程序可能会用旧版本覆盖您的dll文件,这样新版本就会消失。这通常被称为“dll hell”,请参见http://en.wikipedia.org/wiki/DLL_Hell。 - Adrian Grigore
1
微软在Visual Studio 2010中放弃了WinSxS - 运行库现在要么私有部署,要么部署在system32中(http://msdn.microsoft.com/en-us/library/vstudio/dd293574.aspx)。 - BCran
使用 /MD 生成较小的 EXE 的参数与安装程序大小或磁盘上的大小无关:它是为了减少操作系统的内存消耗(包括映像大小和共享堆)。 - codesniffer
显示剩余2条评论

11

/MD选项可能遇到的问题是,目标 CRT 版本可能不存在于用户的计算机上(特别是如果您正在使用最新版本的Visual Studio,而用户却拥有较旧的操作系统)。

在这种情况下,您需要想办法将正确的版本安装到他们的计算机上。


7

来自http://msdn.microsoft.com/en-us/library/2kzt1wy3(VS.71).aspx:

/MT 定义_MT,以便从标准头文件(.h)中选择多线程特定版本的运行时例程。此选项还会导致编译器将库名LIBCMT.lib放置到.obj文件中,以便链接器使用LIBCMT.lib解析外部符号。创建多线程程序需要使用/MT或/MD(或其调试等效项/MTd或/MDd)之一。

/MD 定义_MT和_DLL,以便从标准.h文件中选择多线程和DLL特定版本的运行时例程。此选项还会导致编译器将库名MSVCRT.lib放置到.obj文件中。

使用此选项编译的应用程序静态链接到MSVCRT.lib。该库提供了一层代码,允许链接器解析外部引用。实际的工作代码包含在MSVCR71.DLL中,必须在运行时对与MSVCRT.lib链接的应用程序可用。

当使用定义_STATIC_CPPLIB(/D_STATIC_CPPLIB)的/MD时,它将导致应用程序链接到静态多线程标准C++库(libcpmt.lib),而不是动态版本(msvcprt.lib),同时仍通过msvcrt.lib动态链接到主CRT。

如果我理解正确,那么/MT进行静态链接,而/MD进行动态链接。


2
这个问题是“我应该使用哪一个?”,这不是一个答案。 - Leonard Inkret

3
如果你正在构建使用其他 dll 或 lib 的可执行文件,则首选 /MD 选项,因为这样所有组件都将共享同一库。当然,这个选项应该适用于涉及的所有模块,即 dll/lib/exe。
如果你的可执行文件不使用任何 lib 或 dll,则可以自行决定选择哪个选项。现在差异并不太大,因为共享方面尚未发挥作用。
因此,也许你可以从 /MT 开始运行应用程序,因为没有令人信服的理由,但是当添加了一个 lib 或 dll 时,你可以将其更改为与 lib/dll 相同的 /MD。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接