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

Posted

技术标签:

【中文标题】我应该用 /MD 还是 /MT 编译?【英文标题】:Should I compile with /MD or /MT? 【发布时间】:2010-10-19 22:27:20 【问题描述】:

在 Visual Studio 中,有编译标志 /MD 和 /MT 可让您选择所需的 C 运行时库。

我了解实现上的差异,但我仍然不确定使用哪一个。有什么优点/缺点?

我听说 /MD 的一个优点是,它允许某人更新运行时,(比如可能修补安全问题)并且我的应用程序将从这次更新中受益。虽然对我来说,这似乎是一个非功能:我不希望人们在不让我针对新版本进行测试的情况下更改我的运行时!

一些我很好奇的事情:

这将如何影响构建时间? (大概 /MT 有点慢?) 还有哪些其他影响? 大多数人使用哪一种?

【问题讨论】:

更多信息和建议可以在:***.com/questions/787216 【参考方案1】:

通过与/MD动态链接,

您会接触到系统更新(无论好坏), 您的可执行文件可以更小(因为它没有嵌入库),并且 我相信,至少 DLL 的代码段在所有积极使用它的进程之间共享(减少消耗的 RAM 总量)。

我还发现,在实践中,当使用已使用不同运行时选项构建的静态链接的 3rd 方纯二进制库时,主应用程序中的 /MT 往往比 /MD 更容易引起冲突(因为如果 C 运行时被多次静态链接,特别是如果它们是不同的版本,你会遇到麻烦。

【讨论】:

SxS 减少了系统更新位。 EXE 可以声明它想要的 CRT 版本(想要,而不是获得 - 安全更新可能会否决这一点) 这是否意味着如果我使用 MD 编译并且我的程序依赖于某些 dll,如果它在不存在依赖 dll 的计算机上运行,​​程序将失败? @gerrytan:是的,您需要确保所有要运行该软件的计算机上都存在正在使用的适当 DLL。对此的典型解决方案是让用户安装适当的 MSVC 可再发行包,或使用完成所有工作的安装程序。 @Royi 我不确定,但我认为/MT 在运行时会稍微快一些,因为您的应用不需要每次都搜索运行时函数的实现,我不是专家在这个级别,但我很确定大多数操作系统都会缓存运行时实现,所以你的应用程序将使用缓存的版本,所以差异不会那么大,注意我提到我不确定所以不要采取此评论作为论据。【参考方案2】:

如果您使用的是 DLL,那么您应该选择动态链接的 CRT (/MD)。

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

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

【讨论】:

【参考方案3】:

我相信通过 Visual Studio 构建的项目的默认设置是 /MD。

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

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

附:正如Mr. Fooz 指出的那样,保持一致至关重要。如果您要与其他库链接,则需要使用与它们相同的选项。如果您使用的是第三方 DLL,几乎可以肯定您需要使用运行时库的 DLL 版本。

【讨论】:

【参考方案4】:

我更喜欢使用 /MT 进行静态链接。

即使您确实使用 /MD 获得了较小的可执行文件,您仍然需要提供一堆 DLL 以确保用户获得运行您的程序的正确版本。最后,您的安装程序将比与 /MT 链接时更大。

更糟糕的是,如果您选择将运行时库放在 windows 目录中,用户迟早会安装具有不同库的新应用程序,如果运气不好,会破坏您的应用程序。

【讨论】:

“将运行时库放在 windows 目录中”是个非常糟糕的主意。您可以破坏其他在您之前执行相同操作的愚蠢应用程序。使用 SxS 并让安装程序处理它,或者坚持使用 /MT。 我完全同意这是一个坏主意。不过有些人会这样做,所以我在描述为什么这不是一个好主意。 @AdrianGrigore 为什么具有不同库的新应用程序会导致您的应用程序中断?如果您使用 /MD 链接,您将开始加载新版本的库,对吗? @rturrado:不完全是。在您的应用程序之上安装其他应用程序可能会用旧版本覆盖您的 dll。较新的版本将消失。这就是俗称的“dll地狱”,见en.wikipedia.org/wiki/DLL_Hell Microsoft 在 Visual Studio 2010 中放弃了 WinSxS - 运行时库现在要么私下部署,要么部署在 system32 (msdn.microsoft.com/en-us/library/vstudio/dd293574.aspx) 中。【参考方案5】:

您在使用 /MD 时会遇到的问题是 CRT 的目标版本可能不在您的用户计算机上(尤其是如果您使用的是最新版本的 Visual Studio 并且用户使用的是较旧的操作系统)。

在这种情况下,您必须弄清楚如何将正确的版本安装到他们的机器上。

【讨论】:

【参考方案6】:

来自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 链接的应用程序可用。

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

因此,如果我正确解释它,那么 /MT 静态链接和 /MD 动态链接。

【讨论】:

问题是“我应该使用哪一个?”,这不是答案。【参考方案7】:

如果您正在构建使用其他 dll 或库的可执行文件,则首选 /MD 选项,因为这样所有组件都将共享同一个库。当然,这个选项应该匹配所有涉及的模块,即 dll/lib/exe。

如果您的可执行文件不使用任何 lib 或 dll,而不是任何人的调用。现在差异不是太大,因为共享方面没有发挥作用。

所以也许您可以使用 /MT 启动应用程序,因为没有令人信服的理由,但是当需要添加 lib 或 dll 时,您可以使用 lib/dll 将其更改为 /MD,这很容易。

【讨论】:

以上是关于我应该用 /MD 还是 /MT 编译?的主要内容,如果未能解决你的问题,请参考以下文章

Cef编译 CefSharp编译失败,检测到“RuntimeLibrary”的不匹配项: 值“MT_StaticRelease”不匹配值“MD_DynamicRelease”

如何在MD(d)和MT(d)工程间正确分配和释放动态内存

“/MD /MT”和“dll lib”之间的概念歧义

Qt 和静态库文件 - 如何编译

在 /MT 或 /MD 上 P/调用“受保护的内存”异常

GoogleTest 编译时出现 MT_StaticRelease 错误