0 导言
本文假设读者了解CMake的基础语法。
本文适合C++相关项目。
1 概述
相比传统CMake,现代CMake强化了模块化、标准化的设计思想,提供了大量基于target的设计模式。
编写现代CMake的几个重要思想:
- 核心是Target(构建目标)
- 像编程一样认真对待CMake代码
- 模块化
- 利用CMake提供的Public传播等特性自动管理依赖等关系
- 避免全局更改,而是使用带有作用域的target相关函数
本文内容:
- CMake项目结构
- CMakeLists写法参考
2 CMake项目结构
2.1 目录结构
对于只有单个库的仓库,项目结构如下:
<project_name>/
├── .gitignore
├── CMakeLists.txt
├── README.md
├── inc
│ └── <project_name>
│ └── foo.h
├── src
│ ├── CMakeLists.txt
│ └── foo.cpp
├── tests
│ ├── CMakeLists.txt
│ └── test_foo.cpp
├── cmake
│ ├── FindBar.cmake
│ └── Custom.cmake
└── ext
├── submodule1/
└── submodule2/
其中各个文件夹的命名并不强制,只是一种推荐。例如inc也可以使用include,tests和test也可以互换,ext也可以换成诸如thirdparty等命名。命名清晰即可。
也可以根据需求添加文件夹,如doc,script等。
重要的文件(夹)作用:
- 项目根目录下的CMakeLists.txt被称为主CMakeLists;
- inc包含项目导出的头文件。inc下需要放置一个和项目同名的文件夹,并将头文件放置在其中;
- 非导出的头文件可以自行处置。比如新开一个pri文件夹,或是直接放在src中;
- src包含项目的源码;在src下需要有一个CMakeLists.txt;
- tests包含测试代码;同样需要CMakeLists.txt;
- cmake文件夹包含CMake相关的脚本,包括查找包的脚本和项目使用到的工具脚本;
- ext包含项目用到的三方库;
- 一个推荐的方式是git submodule。
对于有多个子项目的仓库,参考结构如下:
<project_name>/
├── .gitignore
├── CMakeLists.txt
├── README.md
├── subproj1
│ ├── inc
│ ├── src
│ └── CMakeLists.txt
├── subproj2
│ ├── inc
│ ├── src
│ └── CMakeLists.txt
├── cmake
└── ext
其中各个子项目的结构可以参考单库仓库。
2.2 主CMakeLists
主CMakeLists是项目根目录下的CMakeLists.txt。该文件包含的主要内容:
- 项目整体配置
- 项目子文件夹
具体的target等应在各个子文件夹中的CMakeLists中定义。
以下是一个简单的示例:
## 最低版本要求
cmake_minimum_required(VERSION 3.20)
# 也可以指定一个范围
# cmake_minimum_required(VERSION 3.20...3.22)
## 项