本章将通过实际操作,带你创建第一个CMake项目。
我们将从最简单的Hello World程序开始,逐步学习CMake的基本概念和使用方法。

1. 快速体验

让我们从一个最简单的C++项目开始。

02_HelloCMake/
├── CMakeLists.txt
└── src/
    └── main.cpp

1.1 创建C++源文件

这是一个最简单的C++程序,输出 “Hello, CMake!”

#include <iostream>

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

1.2 编写最简单的CMakeLists.txt

虽然CMake支持大写、小写和混合大小写的命令,推荐使用小写命令。

在项目根目录创建CMakeLists.txt文件,只需3行,就能构建一个简单的C++项目:

# 指定CMake的最低版本要求
cmake_minimum_required(VERSION 3.20)

# 定义项目名称
project(HelloCMake)

# 创建可执行文件
add_executable(hello src/main.cpp)

1.2.1 指定最低版本

cmake_minimum_required(VERSION 3.20)

指定运行此CMakeLists.txt所需的最低CMake版本

  • 如果系统CMake版本低于此值,配置将失败
  • CMake会采用指定版本的行为和策略
  • 使用较新版本可以启用现代特性

如何选择版本?

  • 3.15:现代CMake推荐最低版本
  • 3.20:支持C++20和许多新特性
  • 3.25:当前主流推荐版本

还可以指定一个版本范围,如下:

# 指定版本范围
# 意思是:最低3.20,最高测试到3.30
cmake_minimum_required(VERSION 3.20...3.30)

1.2.2 定义项目名称

project(HelloCMake)

定义项目名称,初始化项目设置

  • 设置PROJECT_NAME变量为HelloCMake
  • 默认启用C和C++语言支持
  • 检测编译器并设置相关变量

完整语法:

project(HelloCMake 
    VERSION 1.0.0                      # 项目版本
    DESCRIPTION "Hello CMake Example"  # 项目描述
    LANGUAGES CXX                      # 使用的语言(C、CXX、Fortran等)
)

这会设置以下变量,可以使用message()函数来打印,如下:

# 定义项目名称
# project(HelloCMake) 
# project(HelloCMake VERSION 1.0.0 LANGUAGES CXX) # 只启用 C++
# project(HelloCMake VERSION 1.0.0 LANGUAGES C CXX Fortran Swift) # 会报错,因为没有安装Fortran和Swift的编译器
project(HelloCMake VERSION 1.0.0 DESCRIPTION "Hello CMake Example") 

message(STATUS "Project Name: ${PROJECT_NAME}")                     # HelloCMake
message(STATUS "Project Version: ${PROJECT_VERSION}")               # 1.0.0
message(STATUS "Project Version Major: ${PROJECT_VERSION_MAJOR}")   # 1
message(STATUS "Project Version Minor: ${PROJECT_VERSION_MINOR}")   # 0
message(STATUS "Project Version Patch: ${PROJECT_VERSION_PATCH}")   # 0
message(STATUS "Description: ${PROJECT_DESCRIPTION}")               # Hello CMake Example
message(STATUS "C_Compiler: ${CMAKE_C_COMPILER}")                   # C:/msys64/mingw64/bin/cc.exe
message(STATUS "CPP_Compiler: ${CMAKE_CXX_COMPILER}")               # C:/msys64/mingw64/bin/c++.exe
message(STATUS "CXX_Compiler_ID: ${CMAKE_CXX_COMPILER_ID}")         # GNU

1.2.3 创建可执行文件

add_executable(hello src/main.cpp)

创建一个名为hello的可执行目标

  • hello:目标名称(可执行文件名)
  • src/main.cpp:源文件路径

最终编译完成,在LinuxmacOS系统生成hello,在Windows系统生成hello.exe

1.3 配置

执行cmake命令,它会读取CMakefiles.txt文件,配置生成构建文件Makefile或者build.ninja,如下:

# 该命令用来在指定的目录中生成构建系统文件(例如 CMakeCache.txt、CMakeFiles/、build.ninja、Visual Studio 解决方案等)。
# 只是生成构建文件,不执行编译。
# -B <binary-dir>:指定输出(构建)目录(如果不存在会创建)
# -S <source-dir>:指定源代码目录(如果未指定,则默认为当前工作目录)
cmake -B build 

# 典型用法(推荐,显式源目录):
cmake -S . -B build
# 配置并指定生成器
cmake -S . -B build -G "Ninja"
cmake -S . -B build -G "Unix Makefiles"

终端输出:

yinsh@coding4096 MINGW64 /f/cmake_demos/02_HelloCMake
$ cmake -B build
-- Building for: Ninja
-- The C compiler identification is GNU 15.2.0
-- The CXX compiler identification is GNU 15.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/msys64/ucrt64/bin/cc.exe - skipped
-- Detecting C compile features       
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/msys64/ucrt64/bin/c++.exe - skipped
-- Detecting CXX compile features       
-- Detecting CXX compile features - done
-- Configuring done (1.5s)
-- Generating done (0.0s)
-- Build files have been written to: F:/cmake_demos/02_HelloCMake/build

不论使用ninja构建还是make构建,都会在build目录中,会生成相关的构建文件,如下:

  • make 构建文件

cmake

  • ninja 构建文件

cmake

1.4 构建

build目录中,生成了相关构建文件后,就可以执行以下命令来完成构建,编译出hello.exe文件:

# 方式一:
# cmake --build <build-dir> 是 CMake 提供的统一构建接口
# 用来在指定的构建目录中调用本地构建工具(例如 Ninja、Make、MSBuild、Xcode 等)来实际构建项目
# -v 或 --verbose 选项:会启用 “详细输出(verbose)”,尽可能显示底层构建工具将执行的实际命令和更详细的构建信息。
cmake --build build

# 方式二:
# ninja -C DIR    # change to DIR before doing anything else
ninja -C build    # ninja 构建

# make -C DIRECTORY # Change to DIRECTORY before doing anything.
make -C buid      # make 构建

终端输出:

yinsh@coding4096 MINGW64 /f/cmake_demos/02_HelloCMake
$ cmake --build build --verbose
Change Dir: 'F:/cmake_demos/02_HelloCMake/build'

Run Build Command(s): C:/msys64/ucrt64/bin/ninja.exe -v
[1/2] C:\msys64\ucrt64\bin\c++.exe    -MD -MT CMakeFiles/hello.dir/src/main.cpp.obj -MF CMakeFiles\hello.dir\src\main.cpp.obj.d -o CMakeFiles/hello.dir/src/main.cpp.obj -c F:/cmake_demos/02_HelloCMake/src/main.cpp
[2/2] C:\WINDOWS\system32\cmd.exe /C "cd . && C:\msys64\ucrt64\bin\c++.exe   CMakeFiles/hello.dir/src/main.cpp.obj -o hello.exe -Wl,--out-implib,libhello.dll.a -Wl,--major-image-version,0,--minor-image-version,0  -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 && cd ."

此时,就在build目录下生成了可执行文件hello.exe

1.5 运行

$ ./build/hello.exe 
# 输出:Hello, CMake!

2. 源内构建与源外构建

CMake支持两种构建方式:源内构建(in-source build)和源外构建(out-of-source build)。

2.1 源内构建(不推荐)

源内构建是指在源代码目录中直接运行CMake,生成的所有构建文件与源文件混在一起。

示例:

cd 02_HelloCMake
cmake .      # 在源码目录直接配置
ninja        # 构建

结果目录结构:

02_HelloCMake/
├── CMakeCache.txt          # 生成的缓存文件
├── CMakeFiles/             # 生成的构建文件
├── CMakeLists.txt
├── build.ninja             # 生成的build.ninja
├── cmake_install.cmake     # 安装脚本
├── hello.exe               # 可执行文件
└── src
    └── main.cpp

问题:

  • 混乱的目录结构
    生成的文件和源文件混在一起
    难以区分哪些是源文件,哪些是生成文件
  • 难以清理
    删除生成的文件很麻烦
    可能误删源文件
  • 版本控制困难
    需要在.gitignore中添加大量条目
    容易误提交生成文件
  • 无法多配置构建
    不能同时维护DebugRelease构建
  • CMake官方不推荐
    某些CMake版本会发出警告

2.2 源外构建(强烈推荐)

源外构建是指在源代码目录之外创建一个独立的构建目录,所有生成文件都在这个目录中。

示例:

cd 02_HelloCMake
cmake -S . -B build    # -S指定源码目录,-B指定构建目录
cmake --build build    # 构建

结果目录结构:

02_HelloCMake/
├── CMakeLists.txt              # 源文件(整洁)
├── build                       # 构建目录(所有生成文件都在这里)
│   ├── CMakeCache.txt
│   ├── CMakeFiles/
│   ├── build.ninja
│   ├── cmake_install.cmake
│   └── hello.exe               # 可执行文件
└── src
    └── main.cpp                # 源文件(整洁)

优势:

  • 清洁的源码目录
    源文件和生成文件完全分离
    源码目录保持原始状态

  • 易于清理
    只需删除build目录:rm -rf build
    不会影响源代码

  • 版本控制友好
    .gitignore只需添加:build/
    不会误提交生成文件

  • 支持多配置构建
    可以同时维护多个构建配置
    例如:build-debug/build-release/

  • CMake官方推荐
    所有官方文档和教程都使用源外构建

3. CMake 选项

以上执行命令时,都指定了选项,比如 -S-B-G,可以 cmake -h,查看所有支持的选项,以下列出常用的:

-S <path-to-source>            = Explicitly specify a source directory.
-B <path-to-build>             = Explicitly specify a build directory.
-G <generator-name>            = Specify a build system generator.

--build <dir>                  = Build a CMake-generated project binary tree.
                                 Run "cmake --build" to see compatible
                                 options and a quick help.
--install <dir>                = Install a CMake-generated project binary
                                 tree.  Run "cmake --install" to see
                                 compatible options and a quick help.

-h,-H,--help,-help,-usage,/?   = Print usage information and exit.
--version,-version,/V [<file>] = Print version number and exit.

Generators
The following generators are available on this platform (* marks default):
  Visual Studio 18 2026        = Generates Visual Studio 2026 project files.
                                 Use -A option to specify architecture.
  Visual Studio 17 2022        = Generates Visual Studio 2022 project files.
                                 Use -A option to specify architecture.
  Visual Studio 16 2019        = Generates Visual Studio 2019 project files.
                                 Use -A option to specify architecture.
  Borland Makefiles            = Generates Borland makefiles.
  NMake Makefiles              = Generates NMake makefiles.
  Unix Makefiles               = Generates standard UNIX makefiles.
* Ninja                        = Generates build.ninja files.