【CMake官网】:掌握CMake
1、变量 |
CMake 变量名称区分大小写,且只能包含字母数字字符和下划线
CMAKE_ 变量【存储均为字符串】是CMake 自定义变量,命名应避开
set 可设变量值,第一参数是变量名,其余参数是值
多个参数被打包到 分号分隔的列表 中,并作为字符串存储在变量中
set(Foo "") # 1 quoted arg -> value is ""
set(Foo a) # 1 unquoted arg -> value is "a"
set(Foo "a b c") # 1 quoted arg -> value is "a b c"
set(Foo a b c) # 3 unquoted args -> value is "a;b;c"
变量 VAR 可通过 ${VAR} 引用
若变量未设值,则引用替换为空字符串,否则为变量值
替换是在扩展未引用的参数之前执行的,因此 含分号的变量值 被拆分为0~n个参数
set(Foo a b c) # 3 unquoted args -> value is "a;b;c"
command(${Foo}) # unquoted arg replaced by a;b;c
# and expands to three arguments
command("${Foo}") # quoted arg value is "a;b;c"
set(Foo "") # 1 quoted arg -> value is empty string
command(${Foo}) # unquoted arg replaced by empty string
# and expands to zero arguments
command("${Foo}") # quoted arg value is empty string
CMake 可直接访问 环境变量、Windows注册表值
环境变量:$ ENV{VAR}
注册表项: [HKEY_CURRENT_USER\Software\path1\path2;key] 【路径是从注册表树和键构建】
2、变量范围 |
CMake 中变量作用域略有不同
1、设变量时,对当前及任何子目录的 CMakeLists文件或函数,乃至include包含的文件均可见
2、当处理新子目录或调新函数时,建新变量范围,并使其内所有变量值初始化
3、在子作用域中,对新变量或现有变量更改,均不影响父作用域
// 不影响父作用域:
function(foo)
message(${test}) # test is 1 here
set(test 2)
message(${test}) # test is 2 here, but only in this scope
endfunction()
set(test 1)
foo()
message(${test}) # test will still be 1 here
在子作用域中,让变量影响父作用域:PARENT_SCOPE
function(foo)
message(${test}) # test is 1 here
set(test 2 PARENT_SCOPE)
message(${test}) # test still 1 in this scope
endfunction()
set(test 1)
foo()
message(${test}) # test will now be 2 here
变量是按 set 执行顺序定义的
# FOO is undefined
set(FOO 1)
# FOO is now set to 1
set(FOO 0)
# FOO is now set to 0
变量范围:
set(foo 1)
# process the dir1 subdirectory
add_subdirectory(dir1) //foo
# include and process the commands in file1.cmake
include(file1.cmake) //foo
set(bar 2)
# process the dir2 subdirectory
add_subdirectory(dir2) //foo、bar
# include and process the commands in file2.cmake
include(file2.cmake) //foo、bar
3、命令 |
虽命令名称不区分大小写,但command命名最佳,其和 ( 在同一行,内容就可跨多行
命令参数以空格分隔且区分大小写,"开始"结尾则只表示一参数
值中含 " 须用 \ 转义,可考虑对需要转义的参数可用方括号
值还可用分号来自动扩展参数
command("") # 1 quoted argument
command("a b c") # 1 quoted argument
command("a;b;c") # 1 quoted argument
command("a" "b" "c") # 3 quoted arguments
command(a b c) # 3 unquoted arguments
command(a;b;c) # 1 unquoted argument expands to 3
4、基本命令 |
set 设变量,unset 取消变量
string、list、separate_arguments 提供对字符串和列表的基本操作
add_executable、add_librarycommands 定义要构建的可执行文件和库,以及包含它们的源文件
Visual Studio 项目,显示源文件的同时,若要显示头文件,需将它们添加到可执行文件或库的源文件列表中
5、流量控制 |
流控制结构:
1、条件语句【if】
2、循环结构【foreach、while】
3、程序定义【macro、function】
6、条件语句 |
条件语句【if】:
if(FOO)
# do something here
else()
# do something else
endif()
elseif 顺序测试多条件:
if(MSVC80)
# do something here
elseif(MSVC90)
# do something else
elseif(APPLE)
# do something else
endif()
7、循环构造 |
循环结构【foreach】:
foreach(tfile //变量名
TestAnisotropicDiffusion2D //值列表
TestButterworthLowPass
TestButterworthHighPass
TestCityBlockDistance
TestConvolve
)
add_test(${tfile}-image ${VTK_EXECUTABLE} //循环主题
${VTK_SOURCE_DIR}/Tests/rtImageTest.tcl
${VTK_SOURCE_DIR}/Tests/${tfile}.tcl
-D ${VTK_DATA_ROOT}
-V Baseline/Imaging/${tfile}.png
-A ${VTK_SOURCE_DIR}/Wrapping/Tcl
)
endforeach()
每次循环 tfile 顺序变更值,直到处理完所有值
foreach 可嵌套,还可用循环变量构造变量名:
if(${${tfile}}_TEST_RESULT} MATCHES FAILED)
message("Test ${tfile} failed.")
endif()
循环结构【while】:
#####################################################
# run paraview and ctest test dashboards for 6 hours
#
while(${CTEST_ELAPSED_TIME} LESS 36000)
set(START_TIME ${CTEST_ELAPSED_TIME})
ctest_run_script("dash1_ParaView_vs71continuous.cmake")
ctest_run_script("dash1_cmake_vs71continuous.cmake")
endwhile()
8、过程定义 |
macro、function 支持分散 CMakeLists 中的重复性任务
调函数将建新变量范围,对变量修改仅存于函数内,出函数将释放
function 第一参数是函数名,后续参数均是函数形参
function(DetermineTime _time) //_time 用于传递返回变量的名称
# pass the result up to whatever invoked this
set(${_time} "1:23:45" PARENT_SCOPE) // 影响父作用域
endfunction()
# now use the function we just defined
DetermineTime(current_time)
if(DEFINED current_time)
message(STATUS "The time is now: ${current_time}")
endif()
宏定义和调用方与函数相同
主要区别在于宏不推送和弹出新变量范围,且宏的参数不被视为变量,而是在执行之前就被替换为字符串
第一个参数是宏名,后续参数均是宏形参
# define a simple macro
macro(assert TEST COMMENT)
if(NOT ${TEST})
message("Assertion failed: ${COMMENT}")
endif()
endmacro()
# use the macro
find_library(FOO_LIB foo /usr/local/lib)
assert(${FOO_LIB} "Unable to find library foo")
macro 还支持 可变参数列表,变量参数可用 ARGC 和 ARGV0、ARGV1 等来引用,而非形参
混合形参和可变参数:
# define a macro that takes at least two arguments
# (the formal arguments) plus an optional third argument
macro(assert TEST COMMENT)
if(NOT ${TEST})
message("Assertion failed: ${COMMENT}")
# if called with three arguments then also write the
# message to a file specified as the third argument
if(${ARGC} MATCHES 3)
file(APPEND ${ARGV2} "Assertion failed: ${COMMENT}")
endif()
endif()
endmacro()
# use the macro
find_library(FOO_LIB foo /usr/local/lib)
assert(${FOO_LIB} "Unable to find library foo")
若要将参数作为列表处理,可用 ARGV 和 ARGN
ARGV【与 ARGV0、ARGV1 等相反】是宏的所有参数的列表,而 ARGN 是形参之后的所有参数的列表
return 从函数、目录或文件返回
宏不同于函数,在原地展开,因此无法处理返回
9、正则表达式 |
if、string,可用正则表达式作参数【指定正则有几种不同约定】,如搜索字符串
用基于 Texas Instruments 的开源正则表达式类 可解析 正则表达式
10、高级命令 |
add_dependencies 可在两个目标之间创建依赖关系【至少一目标是自定义目标】
include_regular_expression 可控制 用于跟踪源代码依赖关系的正则表达式【如限制处理某些包含文件】
以前缀 foo 开头,指定正则 ^foo.*$ 以将依赖项检查 限制为仅对项目的文件检查