目录
CMake会首先解析CMakeLists.txt文件——称为配置阶段,然后生成生成环境——称为生成阶段。
生成器表达式是CMake在生成时(即配置之后)构造,用于生成特定于配置的构建输出。使用生成器表达式,我们不必显式地了解位置和名称。换句话说,生成器表达式用于引用仅在生成时已知,但在配置时未知或难于知晓的信息;对于文件名、文件位置和库文件后缀尤其如此。
- 生成器表达式在交叉编译时特别有用,一些可用的信息只有解析 CMakeLists.txt 之后,或在多配置 项目后获取,构建系统生成的所有项目可以有不同的配置,比如Debug和Release。
- 生成器表达式在测试时非常方便,因为不必显式地将可执行程序的位置和名称硬编码到测试中。
生成器表达式的格式为$<...>,生成器表达式可以嵌套。
一、bool生成器表达式
布尔表达式的计算结果为0或1。它们通常用于在条件生成器表达式中构造条件。
1.逻辑运算符
- $<BOOL:string>:如果字符串为空,或者是不区分大小写的0、FALSE、OFF、N、NO、IGNORE、NOTFOUND,或者是以NOTFOUND结尾,则为0;否则为1
- $<AND:conditions>:逻辑与,conditons是以逗号分割的条件列表
- $<OR:conditions>:逻辑或,conditons是以逗号分割的条件列表
- $<NOT:condition>:逻辑非
2.字符串比较
- $<STREQUAL:string1,string2>:判断字符串是否相等
- $<EQUAL:value1,value2>:判断数值是否相等
- $<IN_LIST:string,list>:判断string是否包含在list中,list使用分号分割
- $<VERSION_LESS:v1,v2>:版本号V1小于V2则为1,否则0
- $<VERSION_GREATER:v1,v2>:版本号V1大于V2则为1,否则0
- $<VERSION_EQUAL:v1,v2>:判断版本号是否相等
- $<VERSION_LESS_EQUAL:v1,v2>:版本号V1小于等于V2则为1,否则0
- $<VERSION_LESS_EQUAL:v1,v2>:版本号V1大于等于V2则为1,否则0
3.变量查询
- $<TARGET_EXISTS:target>:target存在则为1
- $<CONFIG:cfgs>:判断编译类型配置是否包含在cfgs列表(比如"release,debug")中;不区分大小写 。eg:$<CONFIG:Debug>
- $<PLATFORM_ID:platform_ids> :判断CMake定义的平台ID是否包含在platform_ids列表中
- $<COMPILE_LANGUAGE:languages>:判断CMake定义的平台ID是否包含在platform_ids列表中。 eg:$<COMPILE_LANGUAGE:CXX>
二、字符串值生成器表达式
扩展为某个字符串。
#根据编译标识,$<CXX_COMPILER_ID>可能为GNU,Clang...
include_directories(/usr/include/$<CXX_COMPILER_ID>/)
字符串值表达式也可以与其他表达式组合使用。
#如果CMAKE_CXX_COMPILER_VERSION小于 4.2.0,则展开到OLD_COMPILER
$<$<VERSION_LESS:$<CXX_COMPILER_VERSION>,4.2.0>:OLD_COMPILER>
1.转义字符
有一些字符有特殊含义,所以可能需要转义,比如常用的$<COMMA>和$<SEMICOLON>,分别表示,和;
2.条件表达式
条件生成器表达式依赖于必须是0或1的布尔条件。
- $<condition:true_string>:如果condition为1则值为true_string,否则为空字符串
- $<IF:condition,true_string,false_string>:如果condition为1则值为true_string,否则为false_string
3.字符串转换:
- $<LOWER_CASE:string>:将字符串转为小写
- $<UPPER_CASE:string>:将字符串转为大写
4.变量查询
- $<CONFIG>:配置名称
- $<PLATFORM_ID>:当前系统的 CMake 平台 ID
- $<CXX_COMPILER_ID>:使用的 CXX 编译器的 CMake 编译器 ID
5.编译目标查询
tgt是由add_executable等创建的可执行目标或者库。
- $<TARGET_NAME_IF_EXISTS:tgt>:如果目标tgt存在,则表示目标名称,否则为空字符串
- $<TARGET_FILE:tgt>:获取编译目标tgt的文件路径
- $<TARGET_FILE_BASE_NAME:tgt>:获取编译目标的基础名字,也就是文件名去掉前缀和扩展名
6.与输出相关的表达式
- $<TARGET_NAME:xxx>:将xxx标记为目标名称,xxx不能包含生成器表达式
三、生成器表达式应用
#有条件地设置相应的库依赖项MPI::MPI_CXX
target_link_libraries(example
PUBLIC
$<$<BOOL:${MPI_FOUND}>:MPI::MPI_CXX>
)
#有条件地设置相应的预处理器HAVE_MPI
target_compile_definitions(example
PRIVATE
$<$<BOOL:${MPI_FOUND}>:HAVE_MPI>
)
可以通过 if 来达到同样的效果:
if(MPI_FOUND)
target_link_libraries(example
PUBLIC
MPI::MPI_CXX
)
target_compile_definitions(example
PRIVATE
HAVE_MPI
)
endif()