7.8.2. Cmake基础知识
7.8.2.1. 变量与缓存
7.8.2.1.1. 本地变量
可以用以下方式申明一个本地(local)变量
set(MY_VARIBLE "value")
变量名通常全部用大写,变量值根在其后,在使用时需要用 ${MY_VARIBLE}。CMake有作用域的概念,在申明一个变量后,你之可以在他的作用域内访问这个变量。如果你将一个汉书或一个文件放到 一个子目录中,这个变量将不再被定义。可以通过在变量申明末尾添加PARENT_SCOPE来将他的作用域定为上一级作用域
示例:
set(MY_LIST "one" "two")
set(MY_LIST "oneltwo") #使用;分割变量
7.8.2.1.2. 缓存变量
CMake提供了一个缓存变量来允许你从命令行中设置变量。CMake中已经有一些预置的变量,像 CMAKE_BUILD_TYPE。如果一个变量还没有被定义,你可以这样申明并设置它
set(MY_CACHE_VARIBLE "value" CACHE STRING "description")
这样写不会覆盖以定义的值,这是为了让你只能在命令行中设置这些变量,而不会在CMake文件执行时被重新覆盖。如果你想把这些变量作为一个临时的全局变量,可以按以下操作
set(MY_CACHE_VARIBLE "value" CACHE STRING "" FORCE) #强制设置该变量的值
mark_as_advanced(MY_CACHE_VARIBLE) #mark_as_advanced修饰以后,用户在执行cmake ../ -L时不会列出该变量
或
set(MY_CACHE_VARIBLE "value" CACHE INTERNAL "")
常见的BOOL类型变量设置
option(MY_OPTION "this is settable from command line" OFF)
7.8.2.1.3. 环境变量
set(ENV{MY_ENV_STRING} value) #设置环境变量
$ENV{MY_ENV_STRING} #获取环境变量
7.8.2.1.4. 缓存
缓存实际上就是个文本文件,CMakeCache.txt,当你运行CMake构建目录时会创建它。CMake可以通过它来记住你设置的所有东西,因此你可以不必在运行CMake的时候再次列出所有的选项。
7.8.2.1.5. 属性
待完善
7.8.2.2. Cmake编程
7.8.2.2.1. 控制流程
CMake有一个if语句可以进行流程控制
if(varible)
# if varible is 'ON', 'YES' , 'TRUE' , 'Y', or non zero number
else()
# if varible is '0' , 'OFF' , 'NO', 'FALSE' , 'N' , 'IGNORE' , 'NOTFOUND' , '""' , or ends in '-NOTFOUND'
endif()
如果CMake版本大于3.1,可以按以下方式写
if("${variable}")
# True if variable is not false-like
else()
# Note that undefined variables would be `""` thus false
endif()
这里有一些关键字可以设置,例如
一元的: NOT , TARGET, EXISTS(文件) , DEFINED等
二元的: STREQUAL, AND, OR, MATCHES(正则表达式),VERSION_LESS, VERSION_LESS_EQUAL
括号可以用来分组
7.8.2.2.2. 宏定义与函数
函数与宏只有作用域上存在区别,宏没有作用域的限制。
示例:
function(SIMPLE REQUIRED_ARG)
message(STATUS "simple arguments: ${REQUIRED_ARG}, followed by ${ARGN}")
set(${REQUIRED_ARG} "From SIMPLE" PARENT_SCOPE)
endfuntion()
simple(This Foo Bar)
message("Output: ${This}")
输出如下
- ::
– Simple argument: This, followed by Foo;Bar Output: From SIMPLE
CMake有一个变量名系统,可以通过cmake_parse_arguments函数来对变量进行命名与解析。
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)
在调用这个函数后,会生成以下变量
COMPLEX_PREFIX_SINGLE = TRUE
COMPLEX_PREFIX_ANOTHER = FALSE
COMPLEX_PREFIX_ONE_VALUE = "value"
COMPLEX_PREFIX_ALSO_ONE_VALUE = <UNDEFINED>
COMPLEX_PREFIX_MULTI_VALURES = "some"
7.8.2.3. Cmake与代码交互
7.8.2.4. 项目组织
示例:
- project
- .gitignore
- README.md
- LICENCE.md
- CMakeLists.txt
- cmake
- FindSomeLib.cmake
- something_else.cmake
- include
- project
- lib.hpp
- src
- CMakeLists.txt
- lib.cpp
- apps
- CMakeLists.txt
- app.cpp
- tests
- CMakeLists.txt
- testlib.cpp
- docs
- CMakeLists.txt
- extern
- googletest
- scripts
- helper.py
7.8.2.5. 在Cmake中运行其他程序
7.8.2.5.1. 配置时运行一条命令
可以使用excute_progress来运行一条命令并获得他的结果。
下面是一个更新所有git子模块的例子
find_package(Git QUIET)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
execute_progress(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIBLE GIT_SUBMOD_RESULT)
if(NOT GIT_SUBMOD_RESULT "0")
message(FATAL_ERROR "git submodule update --init --recursive failed with ${GIT_SUBMOD_RESULT}")
endif()
7.8.2.5.2. 在构建时运行一条命令
find_package(PythonInterp REQUIRED)
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/include/Genetated.hpp"
COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_BINARY_DIR}/scripts/GenerateHeader.py" --argument
DEPENDS some_target)
add_custom_target(generate_header ALL
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/include/Generated.hpp")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/Generated.hpp DESTINATION include)
当你在add_custom_target命令中添加ALL关键字,头文件的生成过程会在some_target这些依赖目标完成后自动执行,当你把这个目标作为下一个目标的依赖,你也可以不加ALL关键字