目录
前言
1. CMake 的基本概念
2. CMake 的基本结构
3. CMake 的核心命令
3.1. cmake_minimum_required
3.2. project
3.3. set
3.4. add_executable 和 add_library
3.5. target_include_directories
3.6. target_link_libraries
3.7. find_package
4. 构建和使用 CMake
4.1. 编写 CMakeLists.txt
4.2. 配置和生成构建文件
4.3. 编译项目
5. 高级 CMake 特性
5.1. 配置头文件
5.2. 使用自定义命令
5.3. 支持多种构建类型
6. 跨平台构建
7. CMake 常用命令总结
8. 复杂项目的组织
前言
CMake 是一个跨平台的构建系统生成工具,用于管理编译过程的自动化,特别适用于大型、复杂的 C/C++ 项目。与 Makefile 不同的是,CMake 可以生成适用于不同平台的构建系统,如 Makefiles、Visual Studio 项目文件等。CMake 的配置文件通常是
CMakeLists.txt
,它包含项目的构建规则。
1. CMake 的基本概念
CMake 的核心功能是生成构建系统。CMake 使用一种称为“生成器”的工具,根据配置文件生成适合特定平台的构建文件,如 Makefile 或 Visual Studio 项目文件。
- CMakeLists.txt:这是 CMake 的配置文件,定义了项目结构、依赖关系、编译选项等。
- 构建目录(Build Directory):CMake 将生成的构建文件放在这个目录中,通常与源代码目录分开。
- 生成器(Generator):指 CMake 用于生成构建文件的工具,如 Unix Makefiles、Ninja、Visual Studio 等。
2. CMake 的基本结构
一个简单的 CMakeLists.txt
文件通常包含以下内容:
cmake_minimum_required(VERSION 3.10)
project(MyProject)set(CMAKE_CXX_STANDARD 11)add_executable(my_program main.cpp utils.cpp)
解释:
cmake_minimum_required
:指定 CMake 的最低版本要求。project
:定义项目的名称。set
:设置变量,这里指定 C++ 标准为 C++11。add_executable
:指定要生成的可执行文件及其源文件。
3. CMake 的核心命令
3.1. cmake_minimum_required
这个命令定义了项目所需的最低 CMake 版本。确保用户使用的 CMake 版本不低于这个版本。
cmake_minimum_required(VERSION 3.10)
3.2. project
定义项目名称及其元数据(如语言类型等)。这个命令会自动定义一些变量,如 PROJECT_NAME
、PROJECT_SOURCE_DIR
等。
project(MyProject VERSION 1.0 LANGUAGES CXX)
3.3. set
用于设置变量值。在 CMake 中,变量通常用 CMAKE_
前缀标识系统变量,而用户自定义变量可以自行命名。
set(CMAKE_CXX_STANDARD 11)
3.4. add_executable
和 add_library
add_executable
:指定要生成的可执行文件。add_library
:指定要生成的库文件(静态库或动态库)。
add_executable(my_program main.cpp utils.cpp)
add_library(my_library SHARED mylib.cpp)
参数说明:
SHARED
:生成动态库。STATIC
:生成静态库(默认)。OBJECT
:生成对象文件。
3.5. target_include_directories
指定目标的头文件搜索路径。通常用于包含外部库的头文件路径。
target_include_directories(my_program PRIVATE ${CMAKE_SOURCE_DIR}/include)
参数说明:
PRIVATE
:只对该目标有效。PUBLIC
:对该目标和依赖该目标的其他目标有效。INTERFACE
:只对依赖该目标的其他目标有效。
3.6. target_link_libraries
为目标指定链接的库。这可以包括静态库、动态库或系统库。
target_link_libraries(my_program PRIVATE my_library)
3.7. find_package
查找并引入外部库或包。CMake 支持多种查找模块,如 FindBoost.cmake
、FindOpenCV.cmake
等。
find_package(Boost REQUIRED COMPONENTS filesystem)
target_link_libraries(my_program PRIVATE Boost::filesystem)
参数说明:
REQUIRED
:如果未找到包,则终止配置。COMPONENTS
:指定要查找的组件。
4. 构建和使用 CMake
假设我们有一个包含 main.cpp
和 utils.cpp
的简单项目,并且头文件在 include/
目录中。
4.1. 编写 CMakeLists.txt
cmake_minimum_required(VERSION 3.10)project(MyProject VERSION 1.0 LANGUAGES CXX)set(CMAKE_CXX_STANDARD 11)include_directories(${CMAKE_SOURCE_DIR}/include)add_executable(my_program src/main.cpp src/utils.cpp)target_include_directories(my_program PRIVATE ${CMAKE_SOURCE_DIR}/include)
4.2. 配置和生成构建文件
在项目根目录下创建一个 build/
目录,并在其中执行 CMake 命令:
mkdir build
cd build
cmake ..
这个过程会生成 Makefile 或其他平台的构建文件。
4.3. 编译项目
使用生成的构建文件来编译项目:
make
执行完这条命令后,my_program
可执行文件将生成在 build/
目录中。
5. 高级 CMake 特性
5.1. 配置头文件
CMake 可以生成配置头文件,通常用于定义一些编译时的常量。
configure_file(${CMAKE_SOURCE_DIR}/config.h.in${CMAKE_BINARY_DIR}/config.h
)target_include_directories(my_program PRIVATE ${CMAKE_BINARY_DIR})
config.h.in
的内容可能如下:
#define PROJECT_VERSION_MAJOR @MyProject_VERSION_MAJOR@
#define PROJECT_VERSION_MINOR @MyProject_VERSION_MINOR@
CMake 会用实际的版本号替换 @...@
中的内容。
5.2. 使用自定义命令
自定义命令可以执行特定任务,如代码生成或数据转换。
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/generated.cppCOMMAND python generate_code.py > ${CMAKE_BINARY_DIR}/generated.cppDEPENDS generate_code.py
)
这个命令将在构建时调用 generate_code.py
脚本生成 generated.cpp
。
5.3. 支持多种构建类型
CMake 支持多种构建类型,如 Debug
、Release
、MinSizeRel
、RelWithDebInfo
。可以通过 CMAKE_BUILD_TYPE
变量进行控制。
cmake -DCMAKE_BUILD_TYPE=Release ..
可以在 CMakeLists.txt 中设置默认的构建类型:
set(CMAKE_BUILD_TYPE Release)
6. 跨平台构建
CMake 的强大之处在于它的跨平台性。CMake 可以为不同的开发环境生成相应的构建文件:
- Unix 系统:生成 Unix Makefile。
- Windows 系统:生成 Visual Studio 项目文件或 NMake Makefiles。
- macOS 系统:生成 Xcode 项目文件。
在 Windows 上使用 Visual Studio:
cmake -G "Visual Studio 16 2019" ..
7. CMake 常用命令总结
cmake_minimum_required
:设置最低 CMake 版本要求。project
:定义项目名称及语言。set
:设置变量。add_executable
/add_library
:定义可执行文件或库。target_include_directories
:设置头文件搜索路径。target_link_libraries
:设置链接的库。find_package
:查找并引入外部库。include_directories
:添加头文件目录。configure_file
:生成配置文件。add_custom_command
:添加自定义构建命令。add_subdirectory
:添加子目录,使其包含的 CMakeLists.txt 文件参与构建。
8. 复杂项目的组织
在复杂项目中,通常会将代码组织为多个子模块,每个子模块都有自己的 CMakeLists.txt
文件。主 CMakeLists.txt
通过 add_subdirectory
将这些模块引入。
示例:
项目结构如下:
MyProject/
│
├── src/
│ ├── main.cpp
│ └── utils.cpp
├── include/
│ └── utils.h
├── lib/
│ ├── CMakeLists.txt
│ └── mylib.cpp
├── CMakeLists.txt
└── build/
主 CMakeLists.txt
文件:
cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0 LANGUAGES CXX)set(CMAKE_CXX_STANDARD 11)add_subdirectory(lib)include_directories(${CMAKE_SOURCE_DIR}/include)add_executable(my_program src/main.cpp src/utils.cpp)target_link_libraries(my_program PRIVATE mylib)
lib/CMakeLists.txt
文件:
add_library(mylib STATIC mylib.cpp)
这个项目将 lib
目录作为一个子模块进行编译,并将其链接到主程序中。