Skip to content

Wiki

CMake Project Template

About 13 min read

Existing English translations were reused. 13 current source blocks remain in Simplified Chinese, without triggering paid translation.

本章用一个支持 Linux 和 Windows 的 CMake 工程模板来讲解 C++ 项目如何组织、构建、安装和引入第三方库。

模板源码见 CMake_Template。当前最低要求为 CMake 3.22,CMakePresets.json 使用格式版本 3,默认 C++ 标准为 C++20。 Ubuntu 22.04 可以直接使用系统软件源提供的 CMake 3.22.1,准备好 Ninja、C++ 编译器和 Eigen 3 后即可构建,无需为本模板升级 CMake。在容器中开发时,这些工具应安装在容器内,供 VSCode CMake Tools 使用。

Linux 使用 GCC;Windows 使用 GCC / MinGW-w64,推荐 MSYS2 UCRT64。还没有准备环境时,先完成 C++开发环境搭建与测试 中自己系统的步骤,再来读本章。

The goal of this template is not to cover all CMake syntax at once, but rather to understand the most commonly used set of modern CMake practices around a real, runnable project:

  1. Top level CMakeLists.txt is only responsible for overall project control.
  2. CMakePresets.json Solidify Debug / Release build configurations.
  3. cmake/ProjectOptions.cmake Save the project's common compilation options.
  4. src/CMakeLists.txt Manage the main program.
  5. Each library directory manages its own source code, header files, installation rules, and third-party dependencies.
  6. Third-party libraries adopt the "whoever uses it, whoever find_package" approach.

1.Template directory structure

The core directory of the template is as follows:

.
├── CMakeLists.txt
├── CMakePresets.json
├── cmake/
│   ├── ProjectOptions.cmake
│   └── WindowsRuntime.cmake
└── src/
    ├── CMakeLists.txt
    ├── main.cpp
    ├── lib1/
    │   ├── CMakeLists.txt
    │   ├── inc/
    │   │   └── lib1/
    │   │       └── eigen3_test.hpp
    │   └── src/
    │       └── eigen3_test.cpp
    └── lib2/
        ├── CMakeLists.txt
        ├── inc/
        │   └── lib2/
        │       └── eigen3_test.hpp
        └── src/
            └── eigen3_test.cpp

Among them:

文件 职责
CMakeLists.txt 顶层入口,声明项目、加载公共配置、进入 src
CMakePresets.json 保存两种平台的 Debug / Release 构建和测试预设
cmake/ProjectOptions.cmake 保存 C/C++ 标准、公共 warning 等配置
cmake/WindowsRuntime.cmake 安装 MinGW 工具链中找到的常用 GCC 运行库
src/CMakeLists.txt 创建最终可执行文件,并链接 lib1、lib2
src/lib1/CMakeLists.txt 创建 lib1_src_lib,管理 lib1 自己的 include、依赖、安装
src/lib2/CMakeLists.txt 创建 lib2_src_lib,管理 lib2 自己的 include、依赖、安装

2.Build command

这个模板使用 CMakePresets + Ninja。下面先按 Linux 展示流程,再给出 Windows 对应命令。两种系统的 configure、build 和 install 原理相同。

Debug build:

cmake --preset linux-debug
cmake --build --preset linux-debug
cmake --install build/linux-debug
./install/linux-debug/bin/cmake_template

Release build:

cmake --preset linux-release
cmake --build --preset linux-release
cmake --install build/linux-release
./install/linux-release/bin/cmake_template

Windows,PowerShell 中的 Debug 构建:

cmake --preset windows-debug
cmake --build --preset windows-debug
cmake --install build/windows-debug
./install/windows-debug/bin/cmake_template.exe

Release 将 windows-debug 改为 windows-release。日常开发直接运行 ./build/windows-debug/bin/cmake_template.exe 即可。

These commands each perform four things:

Command Effect
cmake --preset linux-debug Configure the project and generate Ninja build files
cmake --build --preset linux-debug Compile the source code and link the target
cmake --install build/linux-debug Install the executable files, libraries, and header files to install/linux-debug
./install/linux-debug/bin/cmake_template Run the installed program

During daily development, there is no need to install it every time. After compilation, you can directly run the program in the build directory:

./build/linux-debug/src/cmake_template

install It is more suitable for verifying "whether the installed directory structure and dynamic library paths are correct".

模板保留了 GitHub Actions 中 Linux 和 Windows UCRT64 的 Debug / Release 检查。Windows 检查会移除 PATH 中的开发工具链,再运行整体移动后的安装目录。新增第三方库后,还要补齐自己的依赖和测试。

3.Differences between configure, build, and install

A CMake project generally has three stages:

3.1.configure

cmake --preset linux-debug

At this stage, all CMakeLists.txt and CMakePresets.json are read, the compiler, third-party libraries, and variables are checked, and build system files are generated.

When using Ninja, it generates under build/linux-debug build.ninja.

3.2.build

cmake --build --preset linux-debug

This stage invokes Ninja to compile the .cpp files, generating build artifacts such as .o , .so , and executable files.

3.3.install

cmake --install build/linux-debug

In this phase, according to the install(...) rules, copy the build artifacts to the installation directory.

In this template, Debug is installed to:

install/linux-debug/

Release installed to:

install/linux-release/

The typical structure after installation is as follows:

install/linux-debug/
├── bin/
│   └── cmake_template
├── include/
│   ├── lib1/
│   │   └── eigen3_test.hpp
│   └── lib2/
│       └── eigen3_test.hpp
└── lib64/
    ├── liblib1_src_lib.so
    └── liblib2_src_lib.so

Some Linux distributions use lib, while others use lib64. This template uses GNUInstallDirs to let CMake automatically select the appropriate directory.

Windows 预设使用静态项目库,安装目录的主要结构为:

install/windows-debug/
├── bin/
│   ├── cmake_template.exe
│   └── 常用 GCC 运行库文件
├── include/
│   ├── lib1/eigen3_test.hpp
│   └── lib2/eigen3_test.hpp
└── lib/
    ├── liblib1_src_lib.a
    └── liblib2_src_lib.a

两种平台使用同一份头文件和源文件,库类型由各自的预设选择,后面会逐项解释。

4.Why not write scripts by hand build/install/log

This approach is commonly seen in old-style templates:

  1. Create your own build directory.
  2. In build, run cmake ...
  3. Handwrite make install.
  4. A handwritten script sets LD_LIBRARY_PATH.
  5. Maintain the log directory yourself.

After this template is changed to CMakePresets, none of these contents are needed anymore:

旧做法 新做法
手动 cd build CMakePresets.json 统一设置 binaryDir
手动设置 Debug / Release preset 里设置 CMAKE_BUILD_TYPE
手动设置安装路径 preset 里设置 CMAKE_INSTALL_PREFIX
手动调用 Makefile preset 指定 Ninja
手动设置动态库路径 Linux 设置 INSTALL_RPATH;Windows 静态链接项目库,并安装常用 GCC 运行库
手写 VSCode task VSCode CMake Tools 直接读取 preset
手写复杂调试脚本 VSCode CMake Tools 直接运行或调试当前 CMake target

5.VSCode CMake Tools Running and Debugging

This template does not require writing an additional VSCode debug configuration. After installing CMake Tools, VSCode can directly recognize the executable targets in CMake and run or debug the current target.

A graphical process can be understood as the button version of a command-line process:

Command line VSCode CMake Tools
cmake --preset linux-debug After selecting the Linux Debug preset, Configure
cmake --build --preset linux-debug Click Build
./build/linux-debug/src/cmake_template Select the cmake_template target then click the run button
Debug the build directory artifact with GDB Select the cmake_template target then click the Debug button

CMake Tools typically runs or debugs the executable files in the build directory:

build/linux-debug/src/cmake_template

Therefore, daily development does not require installation every time.install Mainly used to verify the installation layout, header file installation, dynamic library RPATH, and other such content.

Recommended process:

  1. 安装 VSCode CMake Tools 扩展和 Microsoft C/C++ 扩展。
  2. 选择 linux-debug configure preset。
  3. Configure。
  4. Build。
  5. 选择 cmake_template 作为运行/调试 target。
  6. 点击 CMake Tools 提供的运行按钮或 Debug 按钮。

Windows 选择 windows-debug,运行路径对应 build/windows-debug/bin/cmake_template.exe;GDB 要使用 Windows 工具链中的 gdb.exe。界面按钮的含义相同。

For more detailed GUI operation steps, see CMakePresets and Build Installation.

6.Suggested Reading Order for This Chapter

  1. CMakePresets and Build Installation:First understand the preset workflow.
  2. Top-level CMake and Common Compilation Options:Understand the top-level entry and common configuration.
  3. Detailed Explanation of CMake for src and lib Modules:Understand executables, libraries, include, and install.
  4. How to Write Third-Party Library Dependencies:Learn how to introduce libraries such as Eigen, OpenCV, Boost, and PCL.

After completing this, you should be able to:

  1. Create a new C++ project and build it with a preset.
  2. Add a new library directory.
  3. Add a new executable.
  4. Correctly manage header file include paths.
  5. Introduce third-party libraries within a module.
  6. Run the program directly after installation, without relying on handwritten scripts.