cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project (<project-name> VERSION 1.2.3.4)
# CMAKE_PROJECT_NAME
# PROJECT_VERSION
# - PROJECT_VERSION_MAJOR
# - PROJECT_VERSION_MINOR
# - PROJECT_VERSION_PATCH
# - PROJECT_VERSION_TWEAK
# PROJECT_SOURCE_DIR
<project_name>_BINARY_DIR
含project()
的CMakeLists.txt
所在目录的子文件build/
<project_name>_SOURCE_DIR
:含project()
的CMakeLists.txt
所在目录CMAKE_BINARY_DIR
:build/
CMAKE_SOURCE_DIR
:最上级CMakeLists.txt
所在目录CMAKE_CURRENT_BINARY_DIR
:build/
内,CMAKE_CURRENT_SOURCE_DIR
关于CMAKE_SOURCE_DIR
的相对路径加上<project_name>_SOURCE_DIR
CMAKE_CURRENT_SOURCE_DIR
:正在处理的CMakeLists.txt
所在目录CMAKE_CURRENT_LIST_DIR
:正在处理的CMakeLists.txt
所在目录- 当使用
include()
时,该变量与CMAKE_CURRENT_SOURCE_DIR
不同 - (貌似)使用
find_package()
时,该变量与CMAKE_CURRENT_SOURCE_DIR
不同
- 当使用
# normal
set(<variable-name> <value>... [PARENT_SCOPE])
# cache
set(<variable-name> <value>... CACHE <type> <docstring> [FORCE])
# type: BOOL, FILEPATH, PATH, STRING
# FORCE: 每次 configure 都会刷新
-
变量需要区分变量名和变量值,如
var
和${var}
-
变量可以嵌套取值
set(A_A aa) set(var A) message(STATUS "${A_${var}}") # aa
-
字符串 string
-
基础
-
格式
"..."
,如"dd${var}dd"
,"a string"
-
转义字符加双斜杠,如
"...\\n..."
-
特殊字符加单斜杠,如
"...\"..."
-
${var}
不同于"${var}"
set(specialStr "aaa;bbb") # example 1 message(STATUS ${specialStr}) # aaabbb message(STATUS "${specialStr}") # aaa;bbb # example 2 function(PrintVar var) message(STATUS "${var}") endfunction() PrintVar(${specialStr}) # aaa PrintVar("${specialStr}") # aaa;bbb
-
-
find:
string(FIND <string> <substring> <output_variable> [REVERSE])
,未找到则结果为-1
-
manipulation
string(APPEND <string-var> [<input>...]) string(PREPEND <string-var> [<input>...]) string(CONCAT <out-var> [<input>...]) string(JOIN <glue> <out-var> [<input>...]) string(TOLOWER <string> <out-var>) string(TOUPPER <string> <out-var>) string(LENGTH <string> <out-var>) string(SUBSTRING <string> <begin> <length> <out-var>) string(STRIP <string> <out-var>) string(GENEX_STRIP <string> <out-var>) string(REPEAT <string> <count> <out-var>)
-
comparison:
string(COMPARE <op> <string1> <string2> <out-var>)
-
hashing:
string(<HASH> <out-var> <input>)
-
-
列表 list
- 创建:
set(<list_name> <item>...)
或set(<list_name> "${item_0};${item_1};...;${item_n}")
- 创建:
message(STATUS/WARNING/FATAL_ERROR "str")
- 按名传参和按值传参
function(PrintVar var)
message(STATUS "${var}: ${${var}}")
endfunction()
function(PrintValue value)
message(STATUS "${value}")
endfunction()
set(num 3)
PrintVar(num)
PrintValue(${num})
cmake_parse_arguments("ARG" # prefix
<options> # TRUE / FALSE
<one_value_keywords>
<multi_value_keywords> # list
${ARGN})
# 结果为 ARG_*
# - ARG_<option>
# - ARG_<one_value_keyword>
# - ARG_<multi_value_keyword>
- list 作为参数
- 调用时写成
${list}
会被展开成多个参数 - 调用时写成
"${list}"
,函数内部参数即为正常 list - 调用时写成
<list>
,函数内部需使用${arg_list}
得到正常 list
- 调用时写成
- 循环 n 次
set(i 0)
while(i LESS <n>)
# ...
math(EXPR i "${i} + 1")
endwhile()
- 遍历单个 list
foreach(v ${list})
# ... ${v}
endforeach()
- 遍历两个等长 list
list(LENGTH <list0> n)
set(i 0)
while(i LESS n)
list(GET <list0> ${i} v0)
list(GET <list1> ${i} v1)
# ...
math(EXPR i "${i} + 1")
endwhile()
- 遍历结构 list
list(LENGTH <struct_list> n)
set(i 0)
while(i LESS n)
list(SUBLIST <struct_list> ${i} <struct_size> <obj>)
list(GET <obj> 0 <field_0>)
list(GET <obj> 1 <field_1>)
# ...
list(GET <obj> k <field_k>) # k == <struct_size> - 1
# ...
math(EXPR i "${i} + ${struct_size}")
endwhile()
- string
string(REGEX
MATCH
<regular_expression>
<output_variable>
<input> [<input>...])
# 匹配一次
# CMAKE_MATCH_<n>
# - 由 '()' 句法捕获
# - n : 0, 1, ..., 9
# - CMAKE_MATCH_0 == <output_variable>
# - n == CMAKE_MATCH_COUNT
string(REGEX
MATCHALL
<regular_expression>
<output_variable>
<input> [<input>...])
# 匹配多次,结果为 list
# CMAKE_MATCH_* 无用
string(REGEX
REPLACE
<regular_expression>
<replacement_expression>
<output_variable>
<input> [<input>...])
# \1, \2, ..., \9 表示 '()' 捕获的结果
# 在 <replacement_expression> 中需要写成 \\1, \\2, ..., \\9
- list
list(FILTER <list>
INCLUDE/EXCLUDE
REGEX <regular_expression>)
# INCLUDE: 将所有匹配替换成 <list>
# EXCLUDE: 将所有匹配从 <list> 排除
- add: add_executable, add_library
# 1. add target
# 1.1 exe
add_executable(<name> [<source>...])
# 1.2 lib/dll
# 1.2.1 normal
add_library(<name> STATIC|SHARED [<source>...])
# 1.2.2 interface : e.g. pure head files
add_library(<name> INTERFACE)
# 2. alias
add_library(<alias> ALIAS <target>)
# <alias> 可以用命名空间 <namespace>::<id>,如 Ubpa::XXX
- source:
target_sources(<target>
PUBLIC <item>...
PRIVATE <item>...
INTERFACE <item>...
)
# gather sources
file(GLOB_RECURSE sources
# header files
<path>/*.h
<path>/*.hpp
<path>/*.hxx
<path>/*.inl
# source files
<path>/*.c
<path>/*.cc
<path>/*.cpp
<path>/*.cxx
# shader files
<path>/*.vert # glsl vertex shader
<path>/*.tesc # glsl tessellation control shader
<path>/*.tese # glsl tessellation evaluation shader
<path>/*.geom # glsl geometry shader
<path>/*.frag # glsl fragment shader
<path>/*.comp # glsl compute shader
<path>/*.hlsl
# Qt files
<path>/*.qrc
<path>/*.ui
)
# group
foreach(source ${sources})
get_filename_component(dir ${source} DIRECTORY)
if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${dir})
source_group("src" FILES ${source})
else()
file(RELATIVE_PATH rdir ${PROJECT_SOURCE_DIR} ${dir})
if(MSVC)
string(REPLACE "/" "\\" rdir_MSVC ${rdir})
set(rdir "${rdir_MSVC}")
endif()
source_group(${rdir} FILES ${source})
endif()
endforeach()
- definition
target_compile_definitions(<target>
PUBLIC <item>...
PRIVATE <item>...
INTERFACE <item>...
)
# <item> => #define <item>
- include directorie
target_include_directories(mylib PUBLIC
$<BUILD_INTERFACE:<absolute_path>>
$<INSTALL_INTERFACE:<relative_path>> # <install_prefix>/<relative_path>
)
# e.g.
# - <absolute_path>: ${PROJECT_SOURCE_DIR}/include
# - <relative_path>: <package_name>/include
- link library
target_link_libraries(<target>
PUBLIC <item>...
PRIVATE <item>...
INTERFACE <item>...
)
-
Reading
- READ:
file(READ <filename> <out>)
- STRINGS:
file(STRINGS <filename> <variable> [<options>...])
- HASH:
file(<HASH> <filename> <variable>)
<HASH>
:MD5/SHA1/SHA224/SHA256/SHA384/SHA512/SHA3_224/SHA3_256/SHA3_384/SHA3_512
- READ:
-
Writing
- WRITE/APPEND:
file(WRITE/APPEND <filename> <content>...)
- TOUCH:
file(TOUCH [<files>...])
- 若文件不存在,创建空文件
- 若文件存在,则更新访问和/或修改时间
- TOUCH_NOCREATE
- GENERATE:
file(GENERATE OUTPUT <output_file> <INPUT input-file|CONTENT content>)
- 在 generation 阶段 生成文件
- 可添加
CONTIDION <expression>
,其中<expression> == 0/1
- WRITE/APPEND:
-
file system
-
GLOB
file(GLOB/GLOB_RECURSE <out_list> [LIST_DIRECTORIES true|false] # 是否包含目录 [RELATIVE <path>] # 相对路径 [CONFIGURE_DEPENDS] # 将结果的所有文件作为 rebuild 的检测对象 [<globbing-expressions>...] # 简化版的正则表达式 )
<globbing-expressions>
- ref:Linux Programmer's Manual GLOB
?
:匹配单个字符*
:匹配文件名/文件夹名内的任意个字符**
:跨目录匹配任意个字符[...]
:同于正则表达式的[...]
[!...]
:补
-
RENAME:
file(RENAME <oldname> <newname>)
,移动文件或文件夹 -
REMOVE:
file(REMOVE/REMOVE_RECURSE [<files>...])
REMOVE
:删除文件,不能删除文件夹REMOVE_RECURSE
:删除文件或文件夹
-
MAKE_DIRECTORY:
file(MAKE_DIRECTORY [<directories>...])
,递归创建文件夹 -
COPY/INSTALL:
file(COPY/INSTALL <files>... DESTINATION <dir>
,拷贝/安装文件
-
-
path conversion
file(RELATIVE_PATH <variable> <directory> <file>)
file(TO_CMAKE_PATH "<path>" <variable>)
,'/'
file(TO_NATIVE_PATH "<path>" <variable>)
,Windows'\\'
,其他'/'
-
transfer
file(DOWNLOAD <url> <file> [<options>...])
INACTIVITY_TIMEOUT <seconds>
:无响应等待时长TIMEOUT <seconds>
:总等待时长SHOW_PROGReSS
:进度STATUS <variable>
:状态为两个值的 list,前者为 0 时表示无错EXPECTED_HASH <HASH>=<value>
:哈希值
-
<namespace>
,e.g.Ubpa
-
<package_name>
- e.g.
${PROJECT_NAME}_${PROJECT_VERSION_MAJOR}_${PROJECT_VERSION_MINOR}_${PROJECT_VERSION_PATCH}
- e.g.
-
target name:
${PROJECT_NAME}_${relative_path}
,其中/
要转成_
string(REPLACE "/" "_" targetName "${PROJECT_NAME}_${relative_path}")
-
bin, dll, lib path
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/bin") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${PROJECT_SOURCE_DIR}/bin") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${PROJECT_SOURCE_DIR}/bin") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/lib") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${PROJECT_SOURCE_DIR}/lib") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${PROJECT_SOURCE_DIR}/lib") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/lib") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${PROJECT_SOURCE_DIR}/lib") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${PROJECT_SOURCE_DIR}/lib")
-
debug postfix
- dll, lib:
set(CMAKE_DEBUG_POSTFIX d)
- exe:
set_target_properties(<target> PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
- dll, lib:
-
install
install(TARGETS <target>... EXPORT "${PROJECT_NAME}Targets" # 链接 export RUNTIME DESTINATION bin # .exe, .dll LIBRARY DESTINATION "${package_name}/lib" # non-DLL shared library ARCHIVE DESTINATION "${package_name}/lib" # .lib ) install(FILES "${PROJECT_SOURCE_DIR}/include" DESTINATION "${package_name}/include")
-
install export
install(EXPORT "${PROJECT_NAME}Targets" NAMESPACE <namespace> )
-
config
include(CMakePackageConfigHelpers) configure_package_config_file(${PROJECT_SOURCE_DIR}/config/Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" INSTALL_DESTINATION "${package_name}/cmake" # 仅生成文件使用,后续还需要自行 install NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO PATH_VARS "${package_name}/include" ) write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" VERSION ${PROJECT_VERSION} COMPATIBILITY ExactVersion ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake DESTINATION “${PROJECT_NAME}/cmake” )
- cmake -G "Visual Studio 16 2019" -A x64 -S ./ -B ./build