cmake:msvc编译第三方库时使用/MT静态库连接c/c++ runtime library

本文介绍如何在CMake中配置MSVC编译器使用静态链接C/C++运行库,提供了一种无需修改原项目CMakeLists.txt的方法,通过自定义compiler_flags_overrides.cmake脚本来替换默认的/MD选项为/MT。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于在cmake生成msvc工程时静态链接c/c++运行库的问题,很久以前写过一篇博客《cmake设置msvc的运行库(runtime library)塈指定openjpeg使用静态库》。当时的办法是在CMakeLists.txt中加一段代码将C_FLAGS_XXX,CXX_FLAGS_XXX等所有变量中的/MD替换成/MT ,就这样解决了问题。

if(MSVC)     
    # Use the static C library for all build types
    foreach(var 
        CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
        CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
        CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
        CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO
      )
      if(${var} MATCHES "/MD")
        string(REGEX REPLACE "/MD" "/MT" ${var} "${${var}}")
      endif()
    endforeach()    
endif(MSVC)

这个办法的确是解决了问题,但从工程角度也存在一些缺陷。
1.对于自己的项目,如果有多个独立项目要管理,就要对每个项目的CMakeLists.txt中都这样加一段代码,也是挺麻烦的。。。容易出错。
2.如果是编译第三方库,也要用这种办法,就得修改第三方库的cmake脚本,无疑就增加了工程管理的复杂度,更容易出错。

今天找到这篇文章《How can I build my MSVC application with a static runtime?》,才完全解决了我的问题:
msvc默认就是使用/MD选项,在cmake中,这个/MD是在初始化时就被设置的。
CMAKE_C_FLAGS_XXXX,CMAKE_CXX_FLAGS_XXXX等系列变量每一个都对应一个后缀为_INIT的初始变量CMAKE_C_FLAGS_XXXX_INIT,CMAKE_CXX_FLAGS_XXXX_INIT,这些变量中保存的就是编译选项的初始值。
这篇文章虽然写的有些错误,但我明白了它的道理:
基本的原理就是利用CMAKE_USER_MAKE_RULES_OVERRIDE这个cmake变量,定义一个初始化脚本,通过这个初始化脚本可以修改上面所说的_INIT系列变量!!!

如下定义一个名为 compiler_flags_overrides.cmake的脚本,脚本中将_INIT后缀的所有编译器初始化变量中的/MD统统改为/MT

if(MSVC)     
  # Use the static C library for all build types
  MESSAGE(STATUS "link to static  C and C++ runtime lirbary(/MT /MTd)")
  foreach(var 
		CMAKE_C_FLAGS_DEBUG_INIT 
		CMAKE_C_FLAGS_RELEASE_INIT
		CMAKE_C_FLAGS_MINSIZEREL_INIT 
		CMAKE_C_FLAGS_RELWITHDEBINFO_INIT
		CMAKE_CXX_FLAGS_DEBUG_INIT 
		CMAKE_CXX_FLAGS_RELEASE_INIT
		CMAKE_CXX_FLAGS_MINSIZEREL_INIT 
		CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT
    )
    if(${var} MATCHES "/MD")
      string(REGEX REPLACE "/MD" "/MT" ${var} "${${var}}")
      MESSAGE(STATUS  "${var}:${${var}}")
    endif()    
  endforeach()	  
endif(MSVC)


然后在调用cmake生成msvc工程的时候用CMAKE_USER_MAKE_RULES_OVERRIDE指定前面compiler_flags_overrides.cmake脚本的位置,就可以实现/MD/MT的切换了。
大致如下:

cmake .. -G "NMake Makefiles" -DCMAKE_USER_MAKE_RULES_OVERRIDE=$overrides_cmake_path

这样的好处显而易见,不需要修改原项目的CMakeLists.txt,在外部就能控制/MD/MT选项。

#参考资料:

《How can I build my MSVC application with a static runtime?》
《CMAKE_USER_MAKE_RULES_OVERRIDE》

<think>嗯,用户问的是如何指定C++运行库环境。首先,我需要回忆一下C++运行库相关的知识。运行库也就是Runtime Library,通常指的是程序运行需要的动态链接库(DLL)或者静态链接库。不同的编译选项会影响程序使用哪种运行库,比如MT、MD这些选项。 用户可能是在遇到运行库相关的问题,比如程序在别的机器上提示缺少MSVCRxxx.dll,或者想静态链接以减少依赖。这候需要指定运行库的类型。我需要解释清楚如何在不同开发环境中设置这些选项。 首先,Visual Studio的设置方法。在项目属性里,C/C++ -> 代码生成 -> 运行库。这里有四个选项:多线程(MT)、多线程调试(MTd)、多线程DLL(MD)、多线程调试DLL(MDd)。需要说明每个选项的区别,MT静态链接,MD是动态链接,带d的是调试版本。 然后,可能用户会使用CMake。这候需要修改CMakeLists.txt,添加对应的编译选项。比如用target_compile_options设置/MT或者/MD,或者处理不同编译器的情况,比如GCC的-static-libgcc和-static-libstdc++。 还要提到注意事项,比如静态链接可能导致文件变大,动态链接需要确保目标系统有对应的运行库。可能还要提一下Windows上的VC Redistributable包,以及Linux下如何管理依赖库。 另外,用户可能不清楚静态链接和动态链接的区别,需要简要说明两者的优缺点。例如,静态链接将库打包进可执行文件,动态链接则依赖外部DLL,这样文件更小但需要正确部署运行库。 可能还需要提醒,不同运行库之间混用可能导致问题,比如内存管理不一致引发崩溃。所以整个项目要统一运行库设置。 另外,跨平台的情况如何处理?比如在Linux下使用GCC或Clang,可能需要不同的参数,比如-static,或者指定库路径。这候可能需要调整链接器的参数。 总结步骤应该是:1. VS中的设置方法;2. CMake中的配置;3. 其他编译器的处理;4. 注意事项和常见问题。这样结构比较清晰,用户能一步步跟着操作。 最后检查有没有遗漏的点,比如调试版和发布版的区别,是否需要区分/MDd和/MD,以及错误使用可能导致的问题。确保回答全面,覆盖不同场景,帮助用户正确指定运行库环境。在</think> C++ 开发中,指定运行库环境通常指选择程序依赖的 **运行库(Runtime Library)类型**,例如动态链接(DLL)或静态链接(LIB)。这会直接影响程序的可移植性、文件大小和部署方式。以下是常见方法和注意事项: --- ### **一、运行库类型** 在 Windows(MSVC)环境下,主要选项有: - **MT(Multi-threaded)**: 静态链接运行库(`.lib`),无需额外 DLL,但文件较大。 - **MTd**: MT 的调试版本(带调试信息)。 - **MD(Multi-threaded DLL)**: 动态链接运行库(如 `MSVCRxxx.dll`),依赖系统环境,但文件更小。 - **MDd**: MD 的调试版本(仅用于开发环境)。 --- ### **二、如何指定运行库** #### **1. Visual Studio 中设置** - **步骤**: 1. 右键项目 → **属性** → **C/C++** → **代码生成** → **运行库**。 2. 选择 `MT`/`MTd`/`MD`/`MDd`。 - **注意**: 确保所有依赖库(如第三方库)的运行库类型一致,避免冲突。 #### **2. CMake 中指定** 在 `CMakeLists.txt` 中添加编译选项: ```cmake # 动态链接(MD/MDd) target_compile_options(your_target PRIVATE /MD) # Release target_compile_options(your_target PRIVATE /MDd) # Debug # 静态链接(MT/MTd) target_compile_options(your_target PRIVATE /MT) # Release target_compile_options(your_target PRIVATE /MTd) # Debug ``` #### **3. 命令行(MSVC 编译器)** 使用 `/MT` 或 `/MD` 参数: ```bash cl /MT your_code.cpp # 静态链接 cl /MD your_code.cpp # 动态链接 ``` #### **4. Linux/GCC 环境** - **静态链接**: ```bash g++ -static -o your_program your_code.cpp # 强制静态链接所有库(包括 libstdc++) ``` - **动态链接**(默认): ```bash g++ -o your_program your_code.cpp ``` --- ### **三、注意事项** 1. **兼容性问题**: - 若使用 `MT`,程序无需外部 DLL,但需确保所有依赖库也使用 `MT`。 - 若使用 `MD`,目标机器需安装对应版本的 **Visual C++ Redistributable**(如 `MSVCP140.dll`)。 2. **调试与发布版本**: - `MTd`/`MDd` 为调试版本,不可在发布环境使用(性能低且依赖调试库)。 3. **跨平台开发**: - Linux 下默认动态链接,如需静态链接需显式指定 `-static`,但可能引发许可证或兼容性问题。 --- ### **四、常见问题** - **Q**:
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值