CMake C++ 构建系统

FreeGuideOnline 15阅读 2026-07-12

bash sudo apt update sudo apt install cmake


**macOS (Homebrew)**
```bash
brew install cmake

Windowscmake.org/download 下载安装包,安装时勾选“Add CMake to the system PATH”。

验证安装:

cmake --version

必备工具

你需要一个 C++ 编译器(如 GCC、Clang 或 MSVC)以及一个构建工具(make、ninja 或 Visual Studio)。通常系统已自带,无需额外安装。


第一个 CMake 项目

项目结构

hello/
├── CMakeLists.txt
└── main.cpp

main.cpp

#include <iostream>
int main() {
    std::cout << "Hello, CMake!" << std::endl;
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(HelloWorld)
add_executable(hello main.cpp)

构建并运行

外部构建(推荐):在项目根目录新建 build 文件夹并进入,执行配置和构建。

mkdir build && cd build
cmake ..          # 生成构建文件
cmake --build .   # 执行编译
./hello           # 运行程序

cmake .. 表示读取上层目录的 CMakeLists.txt,生成文件到当前目录。这样不会污染源代码目录。


CMakeLists.txt 基础语法

所有 CMake 配置以命令的形式编写,命令不区分大小写,但参数通常大小写敏感。

最小版本与项目声明

cmake_minimum_required(VERSION 3.10)  # 指定最低 CMake 版本
project(MyProject VERSION 1.0 LANGUAGES CXX)  # 项目名、版本、语言
  • project() 会设置一系列变量,如 PROJECT_NAMEPROJECT_VERSION 等。

添加可执行目标

add_executable(app_name source1.cpp source2.cpp ...)

例如:

add_executable(myapp main.cpp utils.cpp)

设置 C++ 标准

set(CMAKE_CXX_STANDARD 17)           # 要求 C++17
set(CMAKE_CXX_STANDARD_REQUIRED ON)  # 强制要求,不满足则报错
set(CMAKE_CXX_EXTENSIONS OFF)        # 禁用编译器扩展

更现代的写法是使用目标属性:

target_compile_features(myapp PUBLIC cxx_std_17)

头文件与源文件管理

添加头文件搜索路径

include_directories(include)   # 影响整个目录,已不推荐
target_include_directories(myapp PRIVATE include)  # 仅对目标 myapp 生效,推荐

PRIVATE 表示该头文件仅在编译本目标时使用,不传播给依赖它的其他目标。
PUBLIC 会将路径传播给依赖者(适用于库的公共头文件),INTERFACE 仅向依赖者暴露(适用于纯头文件库)。

自动收集源文件

不推荐在顶层使用通配符,因为文件增删后 CMake 不会自动重新生成。简单项目可手动列出。
若要使用,可以这样:

file(GLOB SOURCES src/*.cpp src/*.h)
add_executable(myapp ${SOURCES})

但更推荐明确列出,或结合 CONFIGURE_DEPENDS(CMake 3.12+):

file(GLOB SOURCES CONFIGURE_DEPENDS src/*.cpp)

添加库

静态库与动态库

# 静态库
add_library(mylib STATIC src/lib.cpp)
# 动态库
add_library(mylib SHARED src/lib.cpp)
# 由 BUILD_SHARED_LIBS 变量决定类型(默认静态)
add_library(mylib src/lib.cpp)

库的头文件

通常把公共头文件放在单独的 include/ 目录,并设置头文件路径。

add_library(mylib src/lib.cpp)
target_include_directories(mylib PUBLIC include)

链接库

add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE mylib)

PRIVATEmyapp 使用 mylib,但不将 mylib 传播给 myapp 的依赖者。
PUBLICmyapp 的依赖者也能使用 mylib(如 mylib 被暴露在 myapp 的公开头文件中)。
INTERFACE:不自己使用,仅向依赖者传播,常见于纯头文件库。


模块化项目与子目录

当项目变大时,使用 add_subdirectory 集成子项目。

myproject/
├── CMakeLists.txt
├── main.cpp
└── math/
    ├── CMakeLists.txt
    ├── include/
    │   └── math.h
    └── src/
        └── math.cpp

顶层 CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(ModularApp)

add_subdirectory(math)            # 先处理子目录
add_executable(app main.cpp)
target_link_libraries(app PRIVATE math)

math/CMakeLists.txt

add_library(math src/math.cpp)
target_include_directories(math PUBLIC include)

子目录中的目标 math 会自动成为全局可见的目标,可以在顶层链接。


查找外部包

使用 find_package 查找预装库或通过 CMake 导出的包。

find_package(OpenCV REQUIRED)        # 必须找到,否则报错
find_package(Boost COMPONENTS filesystem system REQUIRED)
# 链接
target_link_libraries(myapp PRIVATE ${OpenCV_LIBS} Boost::filesystem Boost::system)

很多包会定义导入目标(如 Boost::filesystem),使用它们更安全,能自动处理头文件路径和依赖。

对于没有 CMake 包的系统库,可以使用手动指定变量:

find_library(LIBNAME libname)
target_link_libraries(myapp PRIVATE ${LIBNAME})

或使用 PkgConfig

find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
target_link_libraries(myapp PRIVATE ${GTK3_LIBRARIES})
target_include_directories(myapp PRIVATE ${GTK3_INCLUDE_DIRS})

构建类型与调试

CMake 支持多种构建类型(通过 CMAKE_BUILD_TYPE 设置)。

cmake -DCMAKE_BUILD_TYPE=Debug ..      # 调试版本,含符号,不优化
cmake -DCMAKE_BUILD_TYPE=Release ..    # 发布版本,优化,无调试符号
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .. # 带符号的优化版本

可在 CMakeLists.txt 中设置默认:

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release)
endif()

编译器警告与优化

target_compile_options(myapp PRIVATE -Wall -Wextra)    # GCC/Clang
# MSVC 可用 /W4
if(MSVC)
    target_compile_options(myapp PRIVATE /W4)
endif()

生成器表达式可以更优雅地处理跨平台选项,但基础项目直接使用条件判读即可。


安装与部署

通过 install 命令指定需要安装的文件和目标。

install(TARGETS myapp DESTINATION bin)
install(TARGETS mylib LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
install(DIRECTORY include/ DESTINATION include)

构建后执行安装:

cmake --install . --prefix /usr/local