cmake 介绍

## 简介

开源、跨平台的构建工具,具体可看官方文档 cmake org。源码可以在 github-cmake 查阅。 历史可以看 cmake history,目前 Android、LLVM、QT 等都默认推荐使用 cmake。 除去官方文档,还有 modern cmake 及其中文版 Modern CMake 简体中文版 可以参看。

以 Android 为例,简单的流程可以理解为:

CMakeLists.txt -> cmake -> Makefile -> make -> so 库

cmake 常用参数

3.31 manual

  1. -G <generator>:指定要使用的构建系统生成器(如 -G Ninja
  2. -D <var>=<value>:定义或覆盖 CMake 变量(如 -D CMAKE_BUILD_TYPE=Release
  3. -S <source_path>:指定源代码路径(如 -S . -B build
  4. -B <build_path>:指定构建目录
  5. -C <initial_cache>:预先加载 CMake 缓存文件
  6. -E <command>:执行 CMake 的内置命令(如:cmake -E make_directory build
  7. --build <build_path>:调用构建工具来构建项目,通常与 --config 一起使用(如 cmake --build build --config Release
  8. --install <build_path>:安装构建的目标到指定位置(如 cmake --install build
  9. --version:显示 CMake 的版本信息
  10. --trace

cmake 命令

以下是 CMake 中几个常用命令的使用简介和示例,整理成表格形式,cmake-commands

脚本命令

以下是 CMake 中更多常用命令的使用简介和示例,以表格形式展示:

命令 简介 示例
block 定义一个代码块,用于组织和控制语句的执行。 block(my_block)<br>message("Inside block")<br>endblock
break 退出循环或块,停止执行当前的循环或块。 foreach(i RANGE 5)<br>if(i EQUAL 3)<br>break<br>endif<br>endforeach
cmake_host_system_information 获取主机系统的信息,如操作系统、处理器架构等。 cmake_host_system_information(RESULT my_os QUERY OS_NAME)
cmake_language 执行 CMake 语言的特定命令,如运行 CMake 脚本。 cmake_language(SET my_var "Hello")
cmake_minimum_required 指定所需的最低 CMake 版本。 cmake_minimum_required(VERSION 3.10)
cmake_parse_arguments 解析传递给函数或宏的参数,便于处理命令行选项。 cmake_parse_arguments(PARSE_VAR my_option "A" "B" "C")
cmake_path 操作路径字符串,例如转换路径格式。 cmake_path(TO_CMAKE_PATH my_path)
cmake_pkg_config 使用 pkg-config 查找库和头文件信息。 cmake_pkg_config(my_lib REQUIRED)
cmake_policy 设置或查询 CMake 的策略。 cmake_policy(SET CMP0012 NEW)
configure_file 处理文件并生成输出文件,通常用于配置头文件。 configure_file(config.h.in config.h)
continue 继续下一个循环迭代,跳过当前的循环体。 foreach(i RANGE 5)<br>if(i EQUAL 3)<br>continue<br>endif<br>endforeach
else 在条件语句中定义 “否则” 的分支。 if(ENABLE_FEATURE)<br>message("Enabled")<br>else<br>message("Disabled")<br>endif
elseif 在条件语句中定义附加的 “如果” 分支。 if(A)<br>message("A")<br>elseif(B)<br>message("B")<br>endif
endblock 结束一个代码块,与 block 搭配使用。 endblock
endforeach 结束 foreach 循环。 foreach(i RANGE 5)<br>message("Number: ${i}")<br>endforeach
endfunction 结束自定义函数的定义。 function(my_function)<br>message("Hello")<br>endfunction
endif 结束 if 语句的分支。 if(CONDITION)<br>message("True")<br>endif
endmacro 结束宏的定义。 macro(my_macro)<br>message("Inside macro")<br>endmacro
endwhile 结束 while 循环。 while(CONDITION)<br>message("Loop")<br>endwhile
execute_process 执行外部命令并获取结果,适合用于运行脚本或命令行工具。 execute_process(COMMAND my_command OUTPUT_VARIABLE result)
file 处理文件相关操作,如复制、删除或读取文件内容。 file(READ "my_file.txt" content)
find_file 查找指定的文件,返回找到的路径。 find_file(MY_FILE my_header.h PATHS /usr/include)
find_library 查找指定的库文件,返回找到的路径。 find_library(MY_LIB my_library PATHS /usr/lib)
find_package 查找并配置指定的包或库,通常与 CMake 模块配合使用。 find_package(MyLib REQUIRED)
find_path 查找指定的目录,返回找到的路径。 find_path(MY_INCLUDE_DIR my_header.h PATHS /usr/include)
find_program 查找指定的程序,返回找到的路径。 find_program(MY_EXEC my_program PATHS /usr/bin)
foreach 对集合中的每个元素执行一段代码。 foreach(item IN LISTS my_list)<br>message("${item}")<br>endforeach
function 定义一个新的 CMake 函数,便于复用代码。 function(my_function)<br>message("Hello")<br>endfunction
get_cmake_property 获取 CMake 变量或属性的值。 get_cmake_property(VERSION VERSION)
get_directory_property 获取当前目录的属性。 get_directory_property(MY_PROPERTY PROPERTIES)
get_filename_component 获取文件路径的组成部分,如文件名或扩展名。 get_filename_component(MY_NAME "path/to/file.txt" NAME)
get_property 获取指定对象的属性,如目标、变量等。 get_property(MY_TARGET_INCLUDE_DIRS my_library INCLUDE_DIRECTORIES)
if 条件判断,执行条件语句。 if(DEFINED MY_VAR)<br>message("Variable is defined")<br>endif
include 包含另一个 CMake 文件或模块,便于代码复用。 include(my_module.cmake)
include_guard 防止 CMake 文件被多次包含,通常用于模块文件。 include_guard(GLOBAL)
list 操作列表,如添加、移除或查找元素。 list(APPEND my_list "new_item")
macro 定义一个新的 CMake 宏,便于复用代码。 macro(my_macro)<br>message("Hello")<br>endmacro
mark_as_advanced 将变量标记为高级变量,不在普通用户界面中显示。 mark_as_advanced(MY_VARIABLE)
math 执行数学计算。 math(EXPR RESULT "5 + 10")
message 输出信息到控制台,便于调试。 message("Building MyProject")
option 定义一个选项变量,通常用于配置开关。 option(MY_OPTION "Enable feature" ON)
return 从函数或宏中返回,终止执行。 function(my_function)<br>return()<br>endfunction
separate_arguments 将字符串分隔为列表。 separate_arguments(MY_LIST "arg1;arg2;arg3")
set 设置变量的值或属性。 set(MY_VAR "Hello, World!")
set_directory_properties 设置当前目录的属性。 set_directory_properties(PROPERTIES MY_PROPERTY "Value")
set_property 设置对象的属性,如目标、目录等。 set_property(TARGET my_library PROPERTY VERSION 1.0)
site_name 获取当前 CMake 项目的站点名称。 message("Site Name: ${CMAKE_SYSTEM_NAME}")
string 执行字符串操作,如拼接、替换或查找。 string(APPEND my_string " World!")
unset 删除变量或属性。 unset(MY_VAR)
variable_watch 监视变量的变化并输出调试信息。 variable_watch(MY_VAR)
while 循环执行,直到条件不再满足。 set(i 0)<br>while(i LESS 5)<br>message("${i}")<br>math(EXPR i "${i} + 1")<br>endwhile

项目命令

命令 一句话简介 示例
add_compile_definitions 添加编译时定义的宏,适用于所有目标。 add_compile_definitions(MY_DEFINE)
add_compile_options 添加编译选项,适用于所有目标。 add_compile_options(-Wall -Wextra)
add_custom_command 创建自定义命令,执行特定的操作,如生成文件。 add_custom_command(OUTPUT output.txt<br>COMMAND echo "Hello" > output.txt)
add_custom_target 创建自定义构建目标,可以与其他目标相互依赖。 add_custom_target(MyTarget DEPENDS output.txt)
add_definitions 添加编译时定义的宏,适用于所有目标(不推荐使用)。 add_definitions(-DMY_DEFINE)
add_dependencies 指定目标间的依赖关系,确保构建顺序。 add_dependencies(my_executable my_library)
add_executable 定义一个可执行文件目标。 add_executable(my_app main.cpp)
add_library 定义一个库目标,可以是静态库或共享库。 add_library(my_library SHARED library.cpp)
add_link_options 添加链接选项,适用于所有目标。 add_link_options(-static)
add_subdirectory 将子目录添加到构建系统中,便于管理大型项目。 add_subdirectory(src)
add_test 注册测试用例,以便使用 CTest 运行。 add_test(NAME MyTest COMMAND my_app)
aux_source_directory 自动查找指定目录中的源文件并将其添加到变量中。 aux_source_directory(src DIR_SOURCES)
build_command 在自定义命令中执行构建操作。 set(BUILD_CMD "make")<br>add_custom_command(OUTPUT output.txt COMMAND ${BUILD_CMD})
cmake_file_api 启用 CMake 文件 API,以支持外部工具访问构建信息。 set(CMAKE_FILE_API TRUE)
create_test_sourcelist 创建一个测试源文件列表,便于管理多个测试文件。 create_test_sourcelist(MyTests test_files.cxx ${CMAKE_SOURCE_DIR}/tests/*.cpp)
define_property 定义自定义属性,允许为目标或其他对象添加新属性。 define_property(MY_PROPERTY TYPE STRING)
enable_language 启用指定的编程语言支持,如 C、C++、Fortran 等。 enable_language(CXX)
enable_testing 启用 CTest 测试框架,允许添加和运行测试。 enable_testing()
export 导出目标及其属性,以供其他 CMakeLists.txt 使用。 export(TARGETS my_library FILE my_library.cmake)
fltk_wrap_ui 为 FLTK 创建用户界面文件的包装器。 fltk_wrap_ui(MY_UIC_FILES my_ui_file.ui)
get_source_file_property 获取源文件的属性,例如编译选项或包含目录。 get_source_file_property(MY_SOURCE my_file.cpp LOCATION)
get_target_property 获取目标的属性,如链接库或编译选项。 get_target_property(MY_LIB_INCLUDE_DIRS my_library INCLUDE_DIRECTORIES)
get_test_property 获取测试的属性,例如期望结果或状态。 get_test_property(MY_TEST TIMEOUT)
include_directories 指定要包含的头文件目录。 include_directories(${CMAKE_SOURCE_DIR}/include)
include_external_msproject 将外部 Microsoft 项目包含到 CMake 项目中。 include_external_msproject(MyProject "path/to/project.vcproj")
include_regular_expression 指定正则表达式以匹配文件,通常用于查找文件。 include_regular_expression("^.*\\.cpp$")
install 定义安装规则,指定如何安装目标和文件。 install(TARGETS my_app DESTINATION bin)
link_directories 指定链接器查找库文件的目录。 link_directories(/usr/local/lib)
link_libraries 指定要链接的库,可以是目标名或库文件。 link_libraries(my_library)
load_cache 从 CMake 缓存加载变量和设置。 load_cache("my_cache.cmake")
project 定义项目的名称和使用的语言。 project(MyProject CXX)
remove_definitions 从编译选项中移除指定的定义宏。 remove_definitions(-DMY_DEFINE)
set_source_files_properties 设置源文件的特定属性,如编译选项或语言标准。 set_source_files_properties(my_file.cpp PROPERTIES LANGUAGE CXX)
set_target_properties 设置目标的特定属性,如输出名称或链接库。 set_target_properties(my_library PROPERTIES VERSION 1.0)
set_tests_properties 设置测试的特定属性,如超时或期望结果。 set_tests_properties(my_test PROPERTIES TIMEOUT 10)
source_group 将源文件组织到特定的组中,以便在 IDE 中更易管理。 source_group("Source Files" FILES main.cpp other.cpp)
target_compile_definitions 为特定目标添加编译时定义的宏。 target_compile_definitions(my_app PRIVATE MY_DEFINE)
target_compile_features 指定特定目标支持的编译特性和语言标准。 target_compile_features(my_app PRIVATE cxx_std_11)
target_compile_options 为特定目标添加编译选项。 target_compile_options(my_app PRIVATE -Wall)
target_include_directories 为特定目标指定包含目录。 target_include_directories(my_library PUBLIC ${CMAKE_SOURCE_DIR}/include)
target_link_directories 为特定目标指定链接库的搜索目录。 target_link_directories(my_app PRIVATE /usr/local/lib)
target_link_libraries 为特定目标指定链接的库或其他目标。 target_link_libraries(my_app PRIVATE my_library)
target_link_options 为特定目标添加链接选项。 target_link_options(my_app PRIVATE -static)
target_precompile_headers 为特定目标指定预编译头文件。 target_precompile_headers(my_app PRIVATE "pch.h")
target_sources 为特定目标添加源文件。 target_sources(my_library PRIVATE source1.cpp source2.cpp)
try_compile 尝试编译一个简单的源文件,测试特性或库的可用性。 try_compile(COMPILER_TEST_BINARY ${CMAKE_BINARY_DIR} test.cpp)
try_run 尝试运行一个可执行文件,测试其行为。 try_run(RUN_TEST_BINARY ${CMAKE_BINARY_DIR} test.cpp)

常用命令详解

定义变量 set(var hello) 使用变量:${var}
math(EXPR ) math(EXPR var "1+1") , ${var} 为2

file(RENAME “test.txt” “new.txt”),文件重命名
file(GLOB ROOT_SOURCE .cpp),GLOB 指令会将所有匹配 .cpp 表达式的文件组成一个列表,并保存在 ROOT_SOURCE 变量中
file(GLOB_RECURSE CORE_SOURCE ./detail/*.cpp),而 GLOB_RECURSE 指令和 GLOB 类似,但是它会遍历匹配目录的所有文件以及子目录下面的文件

预定义的常量 在 CMake 中有许多预定义的常量,使用好这些常量能起到事半功倍的效果。

其他

对于 NDK 18rc 以上版本,gnustl_static 已经不在支持(https://blog.csdn.net/huangkangying/article/details/90048927) 新版本的NDK改用libc++作为默认的STL,而OpenCV Android 3.4版本使用的是gnustl。可以升级到OpenCV 4.0版本来兼容新版本的NDK,或者可以使用libc++重新编译OpenCV

-DANDROID_STL=c++_static or -DANDROID_STL=c++_shared

其他参考

  1. https://www.cnblogs.com/mingfeng002/p/6773217.html
  2. https://glumes.com/post/android/cmake-best-practices/