目录
3.4. add_executable 和 add_library
3.5. target_include_directories
前言
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.cpp
COMMAND python generate_code.py > ${CMAKE_BINARY_DIR}/generated.cpp
DEPENDS 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
目录作为一个子模块进行编译,并将其链接到主程序中。