0. 前言
在MSVC
工程上右键->属性,找到配置属性->C/C++->代码生成->运行库,会发现有好几种选项:MT MTd MD MDd
这是对于多线程程序生成对象链接内容的控制。
先理解一下这四个有什么不同:
- 首先后面带
d
表示Debug
,生成对象(exe、lib
都行)是带有调试信息的,生成对象占用空间相比不带d
的会更大一些; MT
和MD
区别:前者是静态链接,将有关依赖库都打包进生成对象了,所以占用空间更大;后者是动态链接,运行时依赖电脑环境,容易出现换个电脑报错dll的现象。
这个出问题常见于依赖某个lib
文件时,弹出LNK2038
错误:
一般因为VS
工程默认是MD/MDd
,即动态链接方式,而一些库在生成时采用的是MT/MTd
方式(如GoogleTest
),整个项目混合使用二者产生的报错。
1. 如何设置
1.1 CMakeLists代码
先直接上代码,随后讲解要点:
# 设置策略CMP0091为NEW,新策略
if (POLICY CMP0091)
cmake_policy(SET CMP0091 NEW)
endif (POLICY CMP0091)
# 声明一个工程
project(TestpyTest)
# 添加一个exe
add_executable(test test.cpp)
# 设置MT/MTd
set_property(TARGET test PROPERTY
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
1.2 要点1:POLICY
首先是设置POLICY CMP0091
,通过cmake_policy(SET policy NEW)
进行设置;
策略大概可以理解为:cmake
通过选择策略的NEW
或OLD
,可以使用不同的语法,来实现同样的功能。详情可看cmake_policy;
而CMP0091
策略是用来控制MSVC
运行库标志位flags
如何设置的。就拿现在要设置的MT/MD
而言,cmake 3.14
及以前的版本是通过CMAKE_<LANG>_FLAGS_<CONFIG>
变量进行设置的,所以网上会有很多博客说设置MT
的办法大概是:
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
cmake
官方说了,这种字符串的形式不太方便,所以有了新方式,详情可看CMP0091
关于POLICY
设置还有一点需要注意:要在project()之前设置,另外,子项目想要使用,也需要在父项目中设置,否则cmake
之后用VS
打开工程,依然会LNK2038
。
笔者在使用
GoogleTest
时(GoogleTest
库是MTd
),把Test
项目作为子项目,仅在父项目或子项目中添加POLICY
均不行,需要都添加CMP0091
。
1.3 要点2:set_property
首先记住MSVC_RUNTIME_LIBRARY
属性,它的取值可以是:
MultiThreaded
:对应MT
MultiThreadedDLL
:对应MD
MultiThreadedDebug
:对应MTd
MultiThreadedDebugDLL
:对应MDd
这几个取值通过字符串形式设置给MSVC_RUNTIME_LIBRARY
属性,但官方给的字符串是:
"MultiThreaded$<$<CONFIG:Debug>:Debug>"
这用到了cmake
的生成表达式(generator expression
)功能,使得当Config
是Debug
时,自动添加Debug
。使用到了嵌套表达式:
$<CONFIG:Debug>
使用了变量查询的语句,当处于Debug
模式时,该表达式为1
:
- 知道上一条之后,
<$<$<CONFIG:Debug>: Debug>
就变成了$<1或0:Debug>
,使用的是条件表达式,当前部分为1
是该表达式为Debug
,否则为空:
生成表达式可以参考官方:cmake-generator-expressions(7)。
在不设置MSVC_RUNTIME_LIBRARY
属性时,它默认值为MultiThreaded$<$<CONFIG:Debug>:Debug>DLL
,是MD
或MDd
。
更多细节参见官方教程:MSVC_RUNTIME_LIBRARY。