<> 翻译 2.2 CMake 编程

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

流程控制

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

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 命令中使用的关键字,例如:express

  • 一元关键字: 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> 变量起做用。spa

生成器表达式的其余常见用法:翻译

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

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

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 设置您但愿外部世界可见的变量,嵌套函数有点儿烦。 可是,函数不会像宏同样 “泄漏” 变量。 在如下示例中,我将使用函数。htm

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

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 中。

相关文章
相关标签/搜索