cmake_policy 命令

当我们使用 CMake 工具编译项目的 CMakeLists.txt 存在两个问题。
第一个问题是 CMake 工具版本太旧
第二个问题是 CMake 工具版本太新
CMake 工具版本太旧的话,可能 CMakeLists.txt 使用了新的语法,就会不兼容CMake 工具版本太新的话,也会出现不兼容问题,因为 CMake 新版本在更新时 不一定向后兼容,CMake 老版本的一些功能可能删除、更改。为了解决这些差异,保证我们的 cmake 代码始终可用,cmake 从版本 2.0 开始提出了 policy 这个概念。
使用隐式的设置策略。
使用语法:
每个新发布版本一般都会引入一些新的策略,每个策略都会有一个标识号,格式CMP< NNNN >的标识符,< NNNN >对应四个 0 到 9 的整数。每个策略都在文档中描述了 OLD 和 NEW 的行为,以及引入的原因。可以通过如下命令来设置使用哪个版本的策略
< min >: 最小版本, 至少为 2.4, 至多为当前安装的版本号 
< max >: 最大版本, 至少为 < min>

cmake_policy(VERSION< min> [...< max >]) //通过版本来设置策略

使用场景:

  • 如果我们使用了 CMake 新的语法,那么需要通过 cmake_minimum_required() 命令限制 CMake 最低版本需求。
  • 如果 CMake 运行的版本 不在< min >...< max >版本 之间,会报错。
    关于 cmake_minimum_required 和 cmake_policy:
  • 调用cmake_minimum_required会隐式调用cmake_policy(VERSION),指定版本引入的所有策略都将设置为 NEW 行为。
  • 如果没有特别的策略要指定, 可以直接通过调用cmake_minimum_required即可,无需调用 cmake_policy。
    使用示例:
  • CMake 版本 最低为 3.0。
cmake_minimum_required(VERSION 3.0)
# 相当于调用了;
cmake_policy(VERSION 3.0)
  • CMake 版本 最低为 3.0,最高位 3.7。
cmake_minimum_required(VERSION 3.0...3.7)
# 相当于调用了&nbsp;
cmake_policy(VERSION 3.0...3.7)
  • 如果需要运行 的 CMake 版本 高于 3.0,但是引入的策略为 CMake 版本 在 3.0 和 3.5 之间。
cmake_minimum_required(VERSION 3.0)
cmake_policy(VERSION 3.0...3.5)

显式的设置策略
也可以直接使用 cmake_policy 显示设置策略的行为, 为 OLD 或为 NEW。如下:

# 使用 NEW 来声明后续代码依赖于此policy。
cmake_policy(SET CMP< NNNN > NEW)
# 使用OLD来向使用此policy的配置过程发出警告信息。
cmake_policy(SET CMP< NNNN > OLD)

告诉 CMake 对给定的策略使用旧的或新的行为。

  • 依赖于给定策略的旧行为的项目可以通过将策略状态设置为"旧 来消除策略警告。
  • 或者,可以修复项目以使用新行为,并将策略状态设置为 new。
    注意:策略的 OLD 行为一般不可取,因为在未来的版本中可能被抛弃。
    获取当前设置了什么策略
# 使用GET来获取当前支持的policy。
cmake_policy(GET CMP<NNNN> <variable>)

检查策略是否设置为 OLD 或 NEW 行为,值存放到< variable >中。如果没有设置,那么< variable >为空
if (POLICY CMP< CMAKE_POLICY>)
使用此条件来判断当前的 cmake 是否支持某条 policy。
临时设置 policy

  • CMake 将策略设置保存在一个栈结构中,当进入一个项目的子目录时,就会在策略栈中入栈新的一层元素,离开子目录时就会出栈这层元素。因此在一个项目的子目录中设置策略并不会影响父目录以及同层路径,但会影响子目录。
  • 这在一个项目包含了多个分别维护的子目录但在一起编译时非常有用,它可以让不同的子目录使用不同的策略版本。
  • 用户可以使用 cmake_policy 命令来入栈出栈自己的临时策略层,只要入栈和出栈是成对出现的,这对于临时对一小段代码改变策略设置时比较有用。
cmake_policy (PUSH)
#change cmake policy
#do something
cmake_policy (POP)
# PUSH和POP必须是成对的。

说明:
对 cmake_minimum_required(VERSION)、cmake_policy(VERSION) 或 cmake_policy(SET) 命令的调用只影响策略堆栈的当前顶部,影响全局
cmake_policy(PUSH)、cmake_policy(POP) 是临时的,只影响当前子目录

实验一
向一个 CMakeLists.txt 中添加以下内容(new 表示后继代码必须支持此策略):

cmake_policy(SET CMP9999 NEW) # CMP9999 is not defined yet

会发现报错:

> [CMake] CMake Error at CMakeLists.txt:14 (cmake_policy):
1> [CMake]   Policy "CMP9999" is not known to this version of CMake.

实验二:策略中 NEW 与 OLD 的区别
例如,我们在 CMake 3.0 版本中,引入策略 CMP0048。表示在 CMake 3.0 版本中,引入 project() 命令使用 VERSION 设定版本。
默认情况下,cmake-3.19.2 会启用策略 CMP0048。如果不想使用该策略,通过 cmake_policy 命令设置为 OLD。一般设置该策略为 OLD,如果在 project() 命令使用 VERSION 会报错。

if(POLICY CMP0048)
 cmake_policy(SET CMP0048 OLD)
endif()

报错如下:

可以通过 cmake_policy 命令设置为 NEW,使用该策略,这样就不会报错了

if(POLICY CMP0048)
 cmake_policy(SET CMP0048 NEW)
endif()

OLD 相当于强制设置某个策略过期
NEW 相当于强制指定使用某个策略
注意,如果你想要查询 CMP0048 之类的是什么行为,去官网找吧
实验三
当前场景:
假设当前系统上 cmake 的运行版本为 3.0,但是我们cmake_minimum_required(VERSION 2.6) 指定策略版本为 2.6,但是我们要使用cmake 3.0版本引入的CMP0048 怎么办?
也就是说:
我们虽然指定了 CMake 最低运行版本,但是源文件使用了高于 CMake 版本的语法,但是我们不想为了使用了新的语法,而更改 cmake_minimum_required() 命令,那么怎么做?
解决方法:

cmake_minimum_required(VERSION 2.6)
if(POLICY CMP0048)&nbsp;
 cmake_policy(SET CMP0048NEW)
endif()

说明:
对于一些不重要的策略,可以使用一种兼容的手段。
如果运行的 CMake 版本 足够,支持该策略,那么设置为 NEW 行为,因为使用 cmake_minimum_required() 命令通过隐式设置的最新策略为 OLD 行为;
如果运行的 CMake 版本不足够,不支持该策略,那么什么都不做。
实验三

cmake_policy(PUSH)
cmake_policy(SET CMP0057 NEW)
...
if (SOME_ITEM IN_LIST SOME_LIST) # IN_LIST needs CMP0057
...
cmake_policy(POP)

当使用不支持此 policy 的 cmake 版本 configure 时,cmake 会报错并终止 configure 流程:

1> [CMake] CMake Error at CMakeProject1/CMakeLists.txt:15 (cmake_policy):
1> [CMake]   Policy "CMP0057" is not known to this version of CMake.

我们可以使用此方式来声明该段代码必须使用支持此 policy 的 cmake 版本。注意作用域仅限于此段代码。
实验四

cmake_policy(PUSH)
cmake_policy(VERSION 3.15)
list(PREPEND SOME_LIST ${SOME_ITEM}) # PREPEND needs cmake 3.15
cmake_policy(POP)

当使用低于此 version 的 cmake 版本 configure 时,cmake 会报错并终止 configure 流程:

1> [CMake] CMake Error at CMakeProject1/CMakeLists.txt:15 (cmake_policy):
1> [CMake]   An attempt was made to set the policy version of CMake to "3.15" which is
1> [CMake]   greater than this version of CMake.  This is not allowed because the
1> [CMake]   greater version may have new policies not known to this CMake.  You may
1> [CMake]   need a newer CMake version to build this project.

当某个 cmake feature 没有设置特定的 policy 时,我们可以使用此方式来声明该段代码必须使用不低于这个版本的 cmake。注意作用域仅限于此段代码。
参考:
cmake 教程
cmake 教程

posted @ 2022-07-15 13:42  不明白就去明白  阅读(535)  评论(0编辑  收藏  举报