<<Modern CMake>> 翻译 2.2 CMake 编程

流程控制

CMake有一个 if 语句, 经年累月之后,现在它已经相当复杂。 您可以在 if 语句中使用全大写字母书写一系列关键字,并且您通常可以直接通过名称(if语句在历史上出现早于变量扩展)或使用 ${} 语法来引用变量。 下面是 if 语句的示例:

if(variable)
# If variable is `ON`, `YES`, `TRUE`, `Y`, or non zero number
else()
# If variable is `0`, `OFF`, `NO`, `FALSE`, `N`, `IGNORE`, `NOTFOUND`, `""`, or ends in `-NOTFOUND`
endif()
# If variable does not expand to one of the above, CMake will expand it then try again

如果您明确地进行变量扩展(例如 ${variable},由于扩展的潜在扩展),这可能会有点混乱。 在CMake 3.1+ 中添加了一个策略(CMP0054),使得被引号引起来的变量扩展不被递归扩展。 因此,只要 CMake 的最低版本是 3.1+,您就可以:

if("${variable}")
# True if variable is not false-like
else()
# Note that undefined variables would be `""` thus false
endif()

这里还有一些可以在 if 命令中使用的关键字,例如:

  • 一元关键字: NOTTARGETEXISTS (文件), DEFINED, 等等
  • 二元关键字: STREQUALANDORMATCHES (正则表达式), VERSION_LESSVERSION_LESS_EQUAL(CMake 3.7+), 等等
  • 括号可以用于分组

生成器表达式 (Generator-expressions)

Generator-expressions 非常强大,但也有点奇怪和专业。 大多数 CMake 命令在配置时运行,包括上面看到的 if 语句。 但是如果你需要在构建时甚至安装时间执行逻辑呢? 为了这个目的 CMake 添加了生成器表达式(Generator-expressions)。1 它们在目标属性中进行计算和执行。

最简单的生成器表达式是信息表达式,具有这样 $<KEYWORD> 的形式; 他们评估(计算和执行)一条与当前配置相关的信息。 另一种形式是 $<KEYWORD:value>,KEYWORD 关键字控制评估,value 是要评估的项目(这里也允许使用信息表达式关键字)。 如果 KEYWORD 是一个计算结果为 0 或 1 的生成器表达式或变量,value 则替换为 0 或 1。 您可以嵌套生成器表达式,并且可以使用变量来使嵌套变量可读。 某些表达式允许使用逗号分隔的多个值。2

例如,如果你想要设置仅在 DEBUG 配置下生效的编译标志,则可以这样写:

target_compile_options(MyTarget PRIVATE "$<$<CONFIG:Debug>:--my-flag>")

这是一种比使用专用 *_DEBUG 变量更新,更好的方式,并且可以推广到生成器表达式支持的所有情况。 请注意,您永远不应该使用配置时的值作为当前配置,因为 IDE 之类的多配置生成器并没有“当前”配置,仅在构建时通过生成器表达式和自定义的 *_<CONFIG> 变量起作用。

生成器表达式的其他常见用法:

  • 将项目限制为仅限某种语言(例如 CXX),以避免它与 CUDA 等混在一起,或者根据目标语言将其包装以使其不同。
  • 访问配置相关属性,例如目标文件位置。
  • 为构建和安装目录提供不同的位置。

最后一个很常见。几乎每个支持安装的软件包都会看到类似的内容:

 target_include_directories(
MyTarget
PUBLIC
$<BUILD_INTERFACE:"${CMAKE_CURRENT_SOURCE_DIR}/include">
$<INSTALL_INTERFACE:include>
)

1. 它们就像在构建/安装时评估它们一样,但实际上它们是针对每个构建配置分别进行评估的。

2. CMake 文档将表达式拆分为信息,逻辑和输出。

宏和函数

你可以方便的定义你自己的 CMake 函数 function 和宏 macro 。 函数和宏之间的唯一区别是作用范围:宏没有作用范围。 因此,如果您在函数中设置了变量并希望它在外部可见,那么您将需要用 PARENT_SCOPE。 由于您必须在每个函数中明确用 PARENT_SCOPE 设置您希望外部世界可见的变量,嵌套函数有点儿烦。 但是,函数不会像宏一样 “泄漏” 变量。 在以下示例中,我将使用函数。

一个简单使用函数的例子如下:

function(SIMPLE REQUIRED_ARG)
message(STATUS "Simple arguments: ${REQUIRED_ARG}, followed by ${ARGV}")
set(${REQUIRED_ARG} "From SIMPLE" PARENT_SCOPE)
endfunction() simple(This)
message("Output: ${This}")

如果你想用位置参数,它们需要明确列出,并且所有其他参数都被放在 ARGN 中(ARGV 中保存有所有参数,甚至那些你已经列出的参数)。 您只能通过设置变量来解决 CMake 中函数没有返回值的问题。 在上面的示例中,您可以显式指定要设置的变量名称。

参数

你已经在 CMake 函数的大部分使用中看到,CMake 有一个命名变量系统。 您可以将它与 cmake_parse_arguments 函数一起使用。 如果要支持 3.5 以下的 CMake 版本,您还需要包含 CMakeParseArguments 模块,该模块在成为内置命令之前就已存在。

以下是如何使用它的示例:

function(COMPLEX)
cmake_parse_arguments(
COMPLEX_PREFIX
"SINGLE;ANOTHER"
"ONE_VALUE;ALSO_ONE_VALUE"
"MULTI_VALUES"
${ARGN}
) endfunction() complex(SINGLE ONE_VALUE value MULTI_VALUES some other values)

在此调用 cmake_parse_arguments 函数后,在 complex 函数内部,给我们产生了这些变量:

COMPLEX_PREFIX_SINGLE = TRUE
COMPLEX_PREFIX_ANOTHER = FALSE
COMPLEX_PREFIX_ONE_VALUE = "value"
COMPLEX_PREFIX_ALSO_ONE_VALUE = <UNDEFINED>
COMPLEX_PREFIX_MULTI_VALUES = "some;other;values"

如果你查看官方页面,你会看到一个稍微不同的使用 set 的方法避免在列表中明确写分号的方法; 随意使用您最喜欢的结构。 您也可以将它与上面列出的位置参数混合使用; 任何剩余的参数(包括可选的位置参数)都会保存在 COMPLEX_PREFIX_UNPARSED_ARGUMENTS 中。

<<Modern CMake>> 翻译 2.2 CMake 编程的更多相关文章

  1. <<Modern CMake>> 翻译 2. CMake 基础

    <<Modern CMake>> 翻译 2. CMake 基础 最低版本 这是每个 CMakeLists.txt 文件的第一行.CMakeLists.txt 是 CMake 所 ...

  2. <<Modern CMake>> 翻译 1. CMake 介绍

    <<Modern CMake>> 翻译 1. CMake 介绍 人们喜欢讨厌构建系统. 仅仅观看 CppCon17 上的演讲,就可以看到开发人员因为构建系统而闹笑话的例子. 这 ...

  3. <<Modern CMake>> 翻译 2.3 与代码通信

    <<Modern CMake>> 翻译 2.3 与代码通信 配置文件 CMake 允许您使用代码通过 configure_file 存取 CMake 变量. 此命令复制一个文件 ...

  4. <<Modern CMake>> 翻译 2.4 项目目录结构

    <<Modern CMake>> 翻译 2.4 项目目录结构 本节内容有点跑题.但我认为这是一个很好的方法. 我将告诉你如何规划项目的目录. 这是基于惯例,但将帮助您: 轻松阅 ...

  5. Effective Modern C++翻译(1):序言

    /*********************************************************** 关于书: 书是我从网上找到的effective Modern C++的样章,内 ...

  6. mysql配置文件夹错误:在安装mysql 5.6.19 时运行cmake命令是出现CMake Error: The source directory does not appear to contai

    在安装mysql 5.5.xx 时运行cmake命令是出现CMake Error: The source directory does not appear to contain CMakeLists ...

  7. cmake之譬判断cmake的版本

    note 有时候,可能使用的cmake语法 与cmake的版本有关系, 比如modern cmake. 这时候我们可以在 CMAKELISTS.TXT中 判断 cmakeLists.txt 代码 if ...

  8. 源码安装cmake(或者叫升级cmake)

    cmake source install as follows: 0 cd ~ 1 wget https://cmake.org/files/v3.5/cmake-3.5.2.tar.gz 2 tar ...

  9. [书籍翻译] 《JavaScript并发编程》第一章 JavaScript并发简介

    > 本文是我翻译<JavaScript Concurrency>书籍的第一章,该书主要以Promises.Generator.Web workers等技术来讲解JavaScript并 ...

随机推荐

  1. 编译安装python

    编译安装python 1.下载python3的原码包 1.1下载到到opt目录中 cd /opt 1.2下载python3的原码包 wget https://www.python.org/ftp/py ...

  2. memcached--delete--replace--set--get--incr--decr--stats

    memcached命令 1.get  key 来获取在内存中的值 get name 2.delete  key 删除在内存中的值 delete name 3.replace  key flag exp ...

  3. Oracle insert all用法简介

    insert all是oracle中用于批量写数据的 现在直接通过例子学习一下,比较简单直观,例子来自<收获,不止SQL优化>一书 环境准备 create table t as selec ...

  4. 统计学习方法9—EM算法

      EM算法是一种迭代算法,是一种用于计算包含隐变量概率模型的最大似然估计方法,或极大后验概率.EM即expectation maximization,期望最大化算法. 1. 极大似然估计   在概率 ...

  5. .Net之Layui多图片上传

    前言: 多图上传在一些特殊的需求中我们经常会遇到,其实多图上传的原理大家都有各自的见解.对于Layui多图上传和我之前所说的通过js获取文本框中的文件数组遍历提交的原理一样,只不过是Layui中的up ...

  6. 微服务-springcloud-注册中心

    创建服务注册中心(eureka-server) 1.创建项目,选择 Eureka Server 别的都不要选择,next-finish 2.application.yml中写入如下信息:通过eurek ...

  7. POJ 3680:Intervals(最小费用最大流)***

    http://poj.org/problem?id=3680 题意:给出n个区间[Li,Ri],每个区间有一个权值wi,要使得每个点都不被超过k个区间覆盖(最多能被k个区间覆盖),如果选取了第i个区间 ...

  8. LightOJ 1422:Halloween Costumes(区间DP入门)

    http://lightoj.com/volume_showproblem.php?problem=1422 题意:去参加派对,有n场派对,每场派对要穿第wi种衣服,可以选择外面套一件,也可以选择脱掉 ...

  9. Django项目的创建和管理

    1.主题 这部分教程主要介绍如何通过Pycharm创建.管理.运行一个Django工程.对于Django模块的相关知识大家可以参考Python社区. 2.准备环境 Django版本为2.0或更高 Py ...

  10. Java 集合类Hashmap

    一.HashMap 简介 HashMap在程序员的开发过程中是一个十分常用的集合类,它是一个以键值对形式存在的集合类, 在开发中我们可以利用的它的一个key存在即替换的特性,实现一个更新的去重的操作. ...