运行 CMake

现代 CMake 可以直接在根目录下执行指令了,而不是要进入 build 目录:

cmake -B build
cmake --build build

如果想要安装,也只需要一行命令:

cmake --install build

手动指定编译器:

CC=clang CXX=clang++ cmake ..

可以使用 -G"My Tool" 来选择自己想要用的构建工具(GNU Make,MSBuild 等)

基础介绍

CMakeLists.txt 中的第一行指明 CMake 的版本:

cmake_minimum_required(VERSION 3.7...3.29)

if(${CMAKE_VERSION} VERSION_LESS 3.12)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
endif()

设置项目:

project(MyProject VERSION 1.0
DESCRIPTION "Very nice project"
LANGUAGES CXX)

生成可执行文件:

add_executable(one two.cpp three.h)

添加库类似:

add_library(one STATIC two.cpp three.h)

添加 include 目录:

target_include_directories(one PUBLIC include)

target_link_libraries 可以添加一个依赖

设置 C++ 标准:

target_compile_features(calclib PUBLIC cxx_std_11)

可以设定局部变量:

set(MY_VARIABLE "value")
set(MY_LIST "one" "two")

使用变量 ${MY_PATH}

缓存变量可以被从命令行来的变量覆盖:

set(MY_CACHE_VARIABLE "VALUE" CACHE STRING "Description")

对于 BOOL 变量,有不同的方法:

option(MY_OPTION "This is settable from the command line" OFF)

控制流:

if("${variable}")
# True if variable is not false-like
else()
# Note that undefined variables would be `""` thus false
endif()

生成器表达式 generator-expressions 的格式为 $<KEYWORD:value> 表示如果 KEYWORD 计算出为 1,则 value 替换;反之,不替换。如对于 DEBUG 配置的 flag,可以这么做:

target_compile_options(MyTarget PRIVATE "$<$<CONFIG:Debug>:--my-flag>")

除了函数有作用域以外,函数和宏没有什么区别,如:

function(SIMPLE REQUIRED_ARG)
message(STATUS "Simple arguments: ${REQUIRED_ARG}, followed by ${ARGN}")
set(${REQUIRED_ARG} "From SIMPLE" PARENT_SCOPE)
endfunction()

simple(This Foo Bar)
message("Output: ${This}")

ARGN 中保存了未列出的参数

支持配置文件:

Version.h.in
#pragma once

#define MY_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define MY_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define MY_VERSION_PATCH @PROJECT_VERSION_PATCH@
#define MY_VERSION_TWEAK @PROJECT_VERSION_TWEAK@
#define MY_VERSION "@PROJECT_VERSION@"
configure_file (
"${PROJECT_SOURCE_DIR}/include/My/Version.h.in"
"${PROJECT_BINARY_DIR}/include/My/Version.h"
)

一般的项目结构:

- project
- .gitignore
- README.md
- LICENSE.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

在配置时使用 execute_process 来运行程序:

execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE GIT_SUBMOD_RESULT)

构建时运行:

add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/include/Generated.hpp"
COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/scripts/GenerateHeader.py" --argument
DEPENDS some_target)