目录

CMake策略

CMake策略可以用来控制CMake使用新版还是旧版CMake的行为。

策略控制

CMake的策略功能与cmake_minimum_required命令紧密相连,该命令不仅指定了一个项目所需的最小CMake版本,而且还将CMake的行为设置为与所给版本相匹配。然而,一个项目可能需要比cmake_minimum_required命令提供更精细的控制,cmake_policy命令就是用于对策略进行更具体的控制。最简单的形式如下:

1
cmake_policy(VERSION major[.minor[.patch[.tweak]]])

这个形式的cmake_policy命令会改变CMake的行为以匹配指定版本的行为。cmake_minimum_required命令隐含地调用这种形式的cmake_policy命令。除了在项目的顶层必须调用cmake_minimum_required命令外,这两者基本上是可以互换的。当项目需要对某个部分强制执行特定的版本行为时,使用cmake_policy通常能更清楚地传达意图:

1
2
3
4
5
6
7
8
9
cmake_minimum_required(VERSION 3.7)
project(WithLegacy)

# Uses recent CMake features
add_subdirectory(modernDir)

# Imported from another project, relies on old behavior
cmake_policy(VERSION 2.8.11)
add_subdirectory(legacyDir)

CMake 3.12以向允许项目向cmake_minimum_required或cmake_policy(VERSION)指定一个版本范围,表示CMake版本必须至少是最小版本的,而要使用的行为应该是最大版本和正在运行的CMake版本中的较小者。示例如下:

1
2
cmake_minimum_required(VERSION 3.7...3.12)
cmake_policy(VERSION 3.7...3.12)

CMake还提供了单独控制每个行为的能力:

1
2
cmake_policy(SET CMPxxxx NEW)
cmake_policy(SET CMPxxxx OLD)

策略编号为CMPxxxx,其中xxxx总是四位数。通过指定NEW或OLD,可以告诉CMake对该特定策略使用新的或旧的行为。

1
2
3
4
5
# Allow non-existent target with get_target_property()
cmake_policy(SET CMP0045 OLD)

# Would halt with an error without the above policy change
get_target_property(outVar doesNotExist COMPILE_DEFINITIONS)

将一个策略设置为NEW的需求不太常见,以下给出一个例子:

1
2
3
4
5
6
7
cmake_minimum_required(VERSION 3.0)
project(PolicyExample)

if(CMAKE_VERSION VERSION_GREATER 3.1)
    # Enable stronger checking of break() command usage
    cmake_policy(SET CMP0055 NEW)
endif()

测试CMAKE_VERSION变量是确定策略是否可用的一种方法,但if(POLICY ...)形式提供了一种更直接的方法,上述内容也可以如下实现:

1
2
3
4
5
6
7
8
cmake_minimum_required(VERSION 3.0)
project(PolicyExample)

# Only set the policy if the version of CMake being used
# knows about that policy number
if(POLICY CMP0055)
	cmake_policy(SET CMP0055 NEW)
endif()

cmake_policy命令也可以获得某个特定策略的当前状态:

1
cmake_policy(GET CMPxxxx outVar)

存储在outVar中的值为OLD、NEW或空。cmake_minimum_required(VERSION ...)cmake_policy(VERSION ...)命令重置了所有策略的状态。那些在指定的CMake版本或更早引入的策略被重置为NEW,在指定版本之后加入的策略被重置为空。

策略作用域

有时一个策略只需要应用于文件的一个特定部分,离开这个部分后需要恢复策略之前的值,因此进入之前应该手动保存需要改变的任何策略的值。CMake提供了一个策略栈,可以用来简化这一过程:

1
2
cmake_policy(PUSH)
cmake_policy(POP)

通过PUSH操作保存策略状态,POP操作丢弃当前状态并恢复成PUSH前的状态。每个PUSH操作都需要匹配一个POP操作。在这之间,项目可以修改任何策略的设置。策略栈通常用于模块文件中,比如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Save existing policy state
cmake_policy(PUSH)

# Set some policies to OLD to preserve a few old behaviors
cmake_policy(SET CMP0060 OLD) # Library path linking behavior
cmake_policy(SET CMP0021 OLD) # Tolerate relative INCLUDE_DIRECTORIES

# Do various processing here...

# Restore earlier policy settings
cmake_policy(POP)

add_subdirectory、include和find_package命令在处理相应的文件时隐含地调用PUSH和POP操作。include和find_package命令还支持一个NO_POLICY_SCOPE选项,它可以防止策略栈的自动PUSH和POP。