CMake 基础教程
# CMake 教程
CMake是一个开源的扩平台自动化构建系统,用来管理软件构建的程序,并不依赖于某特定编译器,并可支持多层目录、多个应用程序与多个函数库。CMake通过使用简单的配置文件CMakeLists.txt,自动生成不同平台的构建文件(如Makefile、Ninjia构建文件、Visual Studio工程文件等),简化了项目的编译和构建过程。
CMake本身不是构建工具,而是生成构建系统的工具,它生成的构建系统可以使用不同的编译器和工具链。
# CMake 的作用和优势
- 跨平台支持: CMake支持多种操作系统和编译器,使得同一份构建配置可以在不同的环境中使用。
- 简化配置: 通过CMakeLists.txt文件,用户可以定义项目结构、依赖项、编译选项等,无需手动编写复杂的构建脚本
- 自动化构建: CMake能够自动检测系统上的库和工具,较少手动配置的工作量
- 灵活性: 支持多种构建类型和配置(如Debug,Release),并允许用户自定义构建选项和模块。
# 构建配置
- CMakeLists.txt 文件:CMake的配置文件,用于定义项目的构建规则、依赖关系、编译选项等,每个CMake项目通常包含一个或多个CMakeLists.txt文件
- 构建目录:为了保持源代码的整洁,CMake鼓励使用独立的构建目录(Out-of-source构建),这样,构建生成的文件与源代码分开存放。
# 基本工作流程
- 编写CMakeLists.txt文件: 定义项目的构建规则和依赖关系
- 生成构建文件: 使用CMake生成适合当前平台的构建系统文件(例如Makefile、Visual Studio工程文件)
- 执行构建: 使用生成的构建系统文件(如make、ninja、msbuild)来编译项目

# 相关链接
# CMake 安装与配置
CMake 支持的操作系统:
- Microsoft Windows
- Apple macOS
- Linux
- FreeBSD
- OpenBSD
- Solaris
- AIX
# 安装 CMake
CMake可以在不同操作系统上进行安装,CMake安装包下载地址
- Windows
选择Windows版本的安装包(通常是.msi文件),下载后,双击下载的文件,根据提示进行安装。在安装过程中,可以选择将CMake添加到系统的PATH环境变量中(建议选择此选项,以便在命令行中直接使用cmake命令)。安装完成后可以在命令提示符界面输入cmake --version,查看是否能正确显示CMake的版本信息。
- macOS
通过Homebrew安装, brew install cmake,或者通过官方安装包安装,下载.dmg文件并运行,拖动CMake图标到应用程序文件夹。安装成功后,命令都在Applications/CMake.app/Contents/bin目录下,需要将环境变量添加到.bash_profile文件中
vim ~/.bash_profile
export PATH="/Applications/CMake.app/Contents/bin":"$PATH"
2
3
添加完成后,执行source ~/.bash_profile或者重新启动终端,输入cmake --version,确认CMake已正确安装。
- Linux
通过包管理器安装(适用于大多数发行版):
- Ubuntu/Debian:
sudo apt install cmake - Fedora:
sudo dnf install cmake - Arch Linux:
sudo pacman -S cmake
从源码编译安装: 访问CMake官网下载源码包,解压并进入解压后的目录,执行以下命令进行编译和安装
./bootstrap
make
sudo make install
2
3
# 配置 CMake
确保CMake的安装路径被添加到系统的PATH变量中,这样可以在任何位置的命令行中访问CMake
# CMake GUI 使用
CMake也提供了图形用户界面(GUI),可以用于更直观地配置项目。
# CMake 基础
CMakeLists.txt文件是CMake的配置文件,用于定义项目的构建规则、依赖关系、编译选项等。每个CMake项目通常都有一个或多个CMakeLists.txt文件。
# 文件结构和语法
CMakeLists.txt文件使用一系列的CMake指令来描述构建过程,常见的指令包括:
- 指定CMake的最低版本要求:
cmake_minimum_required(VERSION <version>)
# 如
cmake_minimum_required(VERSION 3.10)
2
3
- 定义项目的名称和使用的编程语言:
project(<project_name> [<language> ...])
# 如
project(MyProject CXX)
2
3
- 指定要生成的可执行文件和其源文件:
add_executable(<target> <source_files> ...)
# 如
add_executable(MyExecutable main.cpp other_file.cpp)
2
3
- 创建一个库(静态库或动态库)及其源文件:
add_library(<target> <source_files> ...)
# 如
add_library(MyLibrary STATIC library.cpp)
2
3
- 连接目标文件与其他库:
target_link_libraries(<target> <libraries> ...)
# 如
target_link_libraries(MyExecutable MyLibrary)
2
3
- 添加头文件搜索路径:
include_directories(<dirs> ...)
# 如
include_directories(${PROJECT_SOURCE_DIR}/include)
2
3
- 设置变量的值:
set(<variable> <value> ...)
# 如
set(CMAKE_CXX_STANDARD 11)
2
3
- 设置目标属性:
target_include_directories(TARGET target_name [BEFORE | AFTER] [SYSTEM] [PUBLIC | PRIVATE | INTERFACE] [items1 ...])
# 如
target_include_directories(MyExecutable PRIVATE ${PROJECT_SOURCE_DIR}/include)
2
3
- 安装规则
install(TARGETS target1 [target2 ...]
[RUNTIME DESTINATION dir]
[LIBRARY DESTINATION dir]
[ARCHIVE DESTINATION dir]
[INCLUDES DESTINATION [dir ...]]
[PRIVATE_HEADER DESTINATION dir]
[PUBLIC_HEADER DESTINATION dir])
# 如
install(TARGETS MyExecutable RUNTIME DESTINATION bin)
2
3
4
5
6
7
8
9
- 条件语句(
if、elseif、else、endif命令)
if(expression)
# Commands
elseif(expression)
# Commands
else()
# Commands
endif()
# 如
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
message("Debug build")
endif()
2
3
4
5
6
7
8
9
10
11
- 自定义命令(add_custom_command命令):
add_custom_command(
TARGET target
PRE_BUILD | PRE_LINK | POST_BUILD
COMMAND command1 [ARGS] [WORKING_DIRECTORY dir]
[COMMAND command2 [ARGS]]
[DEPENDS [depend1 [depend2 ...]]]
[COMMENT comment]
[VERBATIM]
)
# 如
add_custom_command(
TARGET MyExecutable POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Build completed"
)
2
3
4
5
6
7
8
9
10
11
12
13
14
一个简单的CMakeLists.txt文件示例:
cmake_minimum_required(VERSION 3.10)
project(MyProject CXX)
# 添加源文件
add_executable(MyExecutable main.cpp)
# 设置C++标准
set(CMAKE_CXX_STANDARD 11)
2
3
4
5
6
7
8
# 变量和缓存
CMake使用变量来存储和传递信息,这些变量可以在CMakeLists.txt文件中定义和使用。变量可以分为普通变量和缓存变量。
# 变量定义与使用
- 定义变量:
set(MY_VAR "Hello World")
- 使用变量:
message(STATUS "Variable MY_VAR is ${MY_VAR}")
# 缓存变量
缓存变量存储在CMake的缓存文件中,用户可以在CMake配置时修改这些值,缓存变量通常用于用户输入的设置,例如编译选项和路径。
- 定义缓存变量
set(MY_CACHE_VAR "DefaultValue" CACHE STRING "A cache variable")
- 使用缓存变量:
message(STATUS "Cache variable MY_CACHE_VAR is ${MY_CACHE_VAR}")
# 查找库和包
CMake可以通过find_package()指令自动检测和配置外部库和包。常用于查找系统安装的库和第三方库。
# find_package() 指令
- 基本用法:
find_package(Boost REQUIRED)
- 指定版本:
find_package(Boost 1.70 REQUIRED)
- 查找库并指定路径:
find_package(OpenCV REQUIRED PATHS /path/to/opencv)
- 使用查找到的库:
target_link_Libraries(MyExecutable Boost::Boost)
- 设置包含目录和链接目录:
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
2
# 使用第三方库
假设需要在项目中使用Boost库,CMakeLists.txt文件如下:
cmake_minimum_required(VERSION 3.10)
project(MyProject CXX)
# 查找 Boost 库
find_package(Boost REQUIRED)
# 添加源文件
add_executable(MyExecutable main.cpp)
# 链接 Boost 库
target_link_libraries(MyExecutable Boost::Boost)
2
3
4
5
6
7
8
9
10
11
# CMake 构建流程
CMake的构建流程分为几个主要步骤,从设置项目到生成和执行构建命令:
- 创建构建目录:保持源代码目录整洁。
- 使用CMake生成构建文件:配置项目并生成适合平台的构建文件。
- 编译和构建:使用生成的构建文件执行编译和构建
- 清理构建文件:删除中间文件和目标文件
- 重新配置和构建:处理项目设置的更改

# 创建构建目录
CMake推荐使用Out-of-source构建方式,即将构建文件放在源代码目录之外的独立目录中。这样可以保持源代码目录的整洁,并方便管理不同的构建配置。

创建构建目录: 在项目的根目录下,创建一个新的构建目录。如,可以创建一个名为build的目录,mkdir build
进入构建目录: 进入刚刚创建的构建目录, cd build
# 使用CMake生成构建文件
在构建目录中运行CMake,以生成适合当前平台的构建系统文件(例如Makefile文件、 Ninja构建文件、 Visual Studio工程文件等)。运行CMake配置: 在构建目录中运行CMake命令,指定源代码目录,源代码目录是包含CMakeLists.txt文件的目录。cmake ..
如果需要指定生成器(如Ninja文件、 Visual Studio文件),可以使用-G选项,如:
cmake -G "Ninja" ..
如果需要指定构建类型(如DEBUG或Release),可以使用-DCMAKE_BUILD_TYPE选项,如:
cmake -DCMAKE_BUILD_TYPE=Release ..
检查配置结果: CMake会输出配置过程中的详细信息,包括找到的库、定义的选项等,如果没有错误,构建系统文件将被生成到构建目录中。
# 编译和构建
使用生成的构建文件进行编译和构建。不同的构建系统使用不同的命令。使用Makefile(或类似构建系统): 如果使用Makefile,可以运行make命令来编译和构建。如果要构建特定的目标,可以指定目标名称,如: make MyExecutable
使用Ninja: 如果使用Ninja构建系统,运行ninja命令来编译和构建项目。与make类似,可以构建特定的目标: ninja MyExecutable
使用Visual Studio: 如果生成了Visual Studio工程文件,可以打开.sln文件,然后在Visual Studio中选择构建解决方案。也可以使用msbuild命令行工具编译: msbuild MyProject.sln /p:Configuration=Release
# 清理构建文件
构建过程中生成的中间文件和目标文件可以通过清理操作删除。
使用Makefile: 运行make clean命令(如果定义了清理规则)来删除生成的文件。
使用Ninja: 运行ninja clean命令(如果定义了清理规则)来删除生成的文件。
手动删除: 可以手动删除构建目录中的所有文件,但保留源代码目录不变,如: rm -rf build/*
# 重新配置和构建
如果修改了CMakeLists.txt文件或项目设置,可能需要重新配置和构建项目。重新运行CMake配置: 在构建目录中重新运行CMake配置命令,cmake ..,重新编译: 使用构建命令重新编译项目,make
# CMake 构建实例
CMake构建步骤:
- 创建CMakeLists.txt文件:
- 创建构建目录: 保持源代码目录整洁
- 配置项目: 使用CMake生成构建系统文件
- 编译项目: 使用构建系统文件编译项目
- 运行可执行文件: 执行生成的程序
- 清理构建文件: 删除中间文件和目标文件
假设有一个简单的C++项目,包含一个主程序文件和一个库文件,使用CMake构建这个项目,项目结构如下:
MyProject/
├── CMakeLists.txt
├── src/
│ ├── main.cpp
│ └── mylib.cpp
└── include/
└── mylib.h
2
3
4
5
6
7
- main.cpp: 主程序源文件
- mylib.cpp: 库源文件
- mylib.h: 库头文件
- CMakeLists.txt: CMake配置文件
- 创建CMakeLists.txt文件
在项目目录下创建CMakeLists.txt文件,CMakeLists.txt文件用于配置CMake项目。
# 指定最低 CMake 版本
cmake_minimum_required(VERSION 3.10)
# 定义项目名称和版本
project(MyProject VERSION 1.0)
# 设置 C++ 标准为 C++11
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 添加头文件搜索路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 添加源文件
# 创建一个库目标 MyLib
add_library(MyLib src/mylib.cpp)
# 创建一个可执行文件目标 MyExecutable
add_executable(MyExecutable src/main.cpp)
# 链接库到可执行文件
target_link_Libraries(MyExecutable MyLib)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
:::info 说明
cmake_minimum_required(VERSION 3.10): 指定CMake的最低版本为3.10project(MyProject VERSION 1.0): 定义项目名称为MyProject,版本为1.0set(CMAKE_CXX_STANDARD 11): 指定C++标准为C++11include_directories(${PROJECT_SOURCE_DIR}/include): 指定头文件目录add_library(MyLib src/mylib.cpp): 创建一个名为MyLib的库,源文件是mylib.cppadd_executable(MyExecutable src/main.cpp): 创建一个名为MyExecutable的可执行文件,源文件是main.cpptarget_link_libraries(MyExecutable MyLib): 将MyLib库链接到MyExecutable可执行文件 :::
- 创建构建目录
为了保持源代码目录的整洁,将在项目根目录下创建一个单独的构建目录。
mkdir build
cd build
2
- 配置项目
在构建目录中使用CMake配置项目,运行CMake配置,将生成适合平台的构建系统文件(如Makefile)
# cmake ..: .. 指向源代码目录,即包含CMakeLists.txt文件的目录,CMake将读取CMakeLists.txt文件并生成构建系统文件。
cmake ..
2
- 编译项目
使用生成的构建系统文件编译项目,根据生成的构建系统文件类型,使用响应的构建命令。使用Makefile,如果生成了Makefile(在大多数类Unix系统中默认生成),可以使用make命令进行编译:
# make: 编译项目生成可执行文件MyExecutable
make
2
- 运行可执行文件
编译完成后,可以运行生成的可执行文件,在构建目录中,运行MyExecutable: ./MyExecutable
- 清理构建文件
清理构建文件以删除生成的中间文件和目标文件,使用make clean,如果在CMakeLists.txt中定义了清理规则,可以使用make clean命令:
# make clean: 删除中间文件和目标文件
make clean
2
如果没有定义清理规则,可以手动删除构建目录中的所有文件: rm -rf build/*
# CMake 高级特性
CMake高级特性允许更灵活地管理和配置CMake项目,以适应复杂的构建需求和环境。
- 自定义CMake模块和脚本: 创建自定义模块和脚本以简化构建过程
- 构建配置和目标: 使用多配置生成器和定义多个构建目标
- 高级查找和配置: 灵活地查找包和配置构建选项
- 生成自定义构建步骤: 添加自定义命令和目标以执行额外的构建操作
- 跨平台和交叉编译: 支持不同平台的构建和交叉编译
- 目标属性和配置: 设置和修改目标属性,以满足特定需求
# 自定义CMake模块和脚本
- 自定义CMake模块
CMake允许创建和使用自定义模块,以简化常见的构建任务,自定义模块包含自定义的CMake脚本和函数。创建自定义模块:
- 在项目目录下创建一个
cmake/目录,用于存放自定义CMake模块 - 在
cmake/目录下创建一个MyModule.cmake文件 - 在CMakeLists.txt文件中包含自定义模块:
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
include(MyModule)
2
自定义模块示例(MyModule.cmake):
function(my_custom_function)
message(STATUS "This is a custom function!")
endfunction()
2
3
- 使用自定义CMake脚本
自定义CMake脚本允许执行自定义配置操作,灵活处理复杂的构建要求。创建自定义脚本:
- 在项目中创建一个脚本文件(如config.cmake)
- 在脚本中编写CMake指令
在CMakeLists.txt文件中调用脚本:
include(${CMAKE_SOURCE_DIR}/config.cmake)