CMake生成器表达式
生成器表达式不在配置阶段计算,而是推迟到生成阶段,当项目文件被写入时再进行计算。它可以用来执行条件逻辑,输出字符串,提供有关构建的各个方面的信息。
简单布尔逻辑
生成器表达式是用$<expr>
的语法指定的,角括号之间的内容可以有几种不同的形式。最简单的条件生成器表达式有以下几种:
|
|
$<1:expr>
:表达式的结果为expr$<0:expr>
:expr被忽略,表达式的结果是一个空字符串。$<BOOL:expr>
:当expr为false时返回0,否则返回1。
生成器表达式也支持逻辑运算:
|
|
expr的值只能为0或1。因为AND、OR和NOT要求expr的值只能为0或1,可以考虑用$<BOOL:...>
来包装这些表达式。
在CMake 3.8及以后的版本中,if-then-else的逻辑可以用$<IF:...>
表达式非常方便地表达出来:
|
|
而在CMake 3.8之前,这个逻辑只能用以下更冗长的方式来表达:
|
|
生成器表达式可以被嵌套,允许构建任意复杂的表达式。下表是一些例子:
表达式 | 结果 | 说明 |
---|---|---|
$<1:foo> | foo | |
$<0:foo> | ||
$true:foo | Error, not a 1 or 0 | |
$<$BOOL:true:foo> | foo | |
$<$NOT:0:foo> | foo | |
$<$NOT:1:foo> | ||
$<$NOT:true:foo> | foo | Error, NOT requires a 1 or 0 |
$<$AND:1,0:foo> | ||
$<$OR:1,0:foo> | foo | |
$<1:$<$BOOL:false:foo» | ||
$<IF:$BOOL:${foo},yes,no> | yes or no | 结果取决于${foo}。 |
和if命令一样,生成器表达式也支持对字符串、数字和版本测试。如下:
|
|
另一个非常有用的条件表达式是测试构建类型:
|
|
如果arg与实际的构建类型相对应,表达式计算为1,否则为0。常见的用法是为构建提供编译开关,比如:
|
|
目标详情
生成器表达式的另一个常见用途是提供关于目标的信息。目标的任何属性都可以通过以下两种形式中的一种获得:
|
|
第一种形式从指定的目标中获取属性值,第二种形式从正在使用生成器表达式的目标中获取属性值。虽然TARGET_PROPERTY是一个非常灵活的表达式类型,但它并不总是获取目标信息的最佳方式。CMake还提供了其他表达式,比如以下几个表达式:
- TARGET_FILE:获取目标二进制文件的绝对路径和文件名。
- TARGET_FILE_NAME:TARGET_FILE相同,但不包括路径。
- TARGET_FILE_DIR:与TARGET_FILE相同,但不包括文件名,这是获得目标目录的最可靠的方法。
除了TARGET_FILE表达式之外,CMake还提供了一些特定于库的表达式,这些表达式的名字以TARGET_LINKER_FILE和TARGET_SONAME_FILE开头。
CMake允许将一个库目标定义为一个对象库,它不是通常意义上的库,只是一个对象文件的集合。因为它们是对象文件,所以不能作为一个单元被链接。相反,它们必须以添加源文件的相同方式添加到目标中。然后CMake在链接阶段包括这些对象文件,就像编译目标的源文件所创建的对象文件一样。这是用$<TARGET_OBJECTS:...>
生成器表达式完成的,它以适合add_executable或add_library使用的形式列出对象文件。如下:
|
|
通用表达式
以下列出一些比较常见的表达式:
$<CONFIG>
:测试构建类型。优先使用这个,而不是CMAKE_BUILD_TYPE变量,因为该变量不能用于多配置项目生成器。$<PLATFORM_ID>
:识别构建目标的平台。这在交叉编译的情况下很有用,特别是当一个构建可能支持多个平台时。这个表达式与CMAKE_SYSTEM_NAME变量密切相关。$<C_COMPILER_VERSION>
,$<CXX_COMPILER_VERSION>
:在某些情况下,我们可能想用特定版本的编译器。比如$<$<VERSION_LESS:$<CXX_COMPILER_VERSION>,4.2.0>:OLD_COMPILER>
。$<LOWER_CASE:…>
,$<UPPER_CASE:…>
:转换大小写,常用于字符串比较,比如$<STREQUAL:$<UPPER_CASE:${someVar}>,FOOBAR>
。