CMakeLists.txt 文件
**CMakeLists.txt **是 CMake 的配置文件,用于定义项目的构建规则、依赖关系、编译选项等。
每个 CMake 项目通常都有一个或多个 CMakeLists.txt 文件。
文件结构和基本语法
指定CMake 最低版本要求
cmake_minimum_required(VERSION
例如 : cmake_minimum_required(VERSION 3.10)
定义项目的名称和使用的编程语言
project(
例如:project(MyProject CXX)
指定要生成的可执行文件和其源文件
add_executable(
例如:add_executable(MyExecutable main.cpp other_file.cpp)
set 用法
在 CMake 中,set 命令用于设置变量的值,可以用于控制编译选项、路径、库文件、编译器等
设置普通变量
1 | set(<variable> <value>... [PARENT_SCOPE]) |
<variable>: 变量名(可以是任意合法的标识符,通常使用大写字母,单词之间用下划线分隔,如MY_PROJECT_NAME)。<value>: 变量的值。可以是一个或多个字符串。如果提供了多个值,CMake 会将它们存储为一个列表(List)。[PARENT_SCOPE]: 这是一个可选的关键字。如果指定了它,变量的值将被设置在父作用域中。这在函数(function)或宏(macro)内部修改外部变量时非常有用。
举例:
1 | # 设置一个名为 PROJECT_NAME 的变量,其值为 "MyAwesomeProject" |
aux_source_directory()
aux_source_directory() 是一个辅助命令,它的核心作用是:
自动查找指定目录下的所有源文件(默认是 .c 和 .cpp 等),并将这些文件的路径列表存储到一个变量中。
基本用法: aux_source_directory(
<dir>: 要搜索的目录路径。可以是相对路径(相对于当前CMakeLists.txt文件所在的目录)或绝对路径。<variable>: 用于存储找到的源文件列表的变量名。
举例
项目结构:
1 | MyProject/ |
cmake
1 | cmake_minimum_required(VERSION 3.10) |
include_directories() 是一个用于 指定编译器在何处查找头文件(.h, .hpp 等 的 CMake 命令。
当你的 C++ 代码中使用 #include 指令时,编译器需要知道去哪里寻找对应的头文件。include_directories() 就是用来告诉 CMake,将哪些目录添加到编译器的头文件搜索路径(-I 标志)中。
例如:include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
file()
CMake 中非常强大和常用的 file() 命令
通过CMake制作库文件
add_library() 命令用于创建一个库目标。库是一种可重用的代码集合,编译后生成 .a (静态库)、.so (动态库) 或 .dll (Windows 动态库) 等文件。
基本用法
1 | target_link_libraries(<target> <PRIVATE|PUBLIC|INTERFACE> <library>...) |
<target>: 你要链接库的目标,可以是一个可执行文件(由add_executable创建)或另一个库(由add_library创建)。<PRIVATE|PUBLIC|INTERFACE>: 要链接的库的名称。这个名称可以是: - 你项目中其他 `add_library` 定义的目标名称(如 `calc`)。 - 系统库的名称(如 `pthread`)。 - 一个完整的库文件路径(不推荐,但有时必要)。1
2
3
4
5
6
7
8
9
10
11
12
13
: 这是
作用域关键字
,用于控制依赖的传递性。
- **`PRIVATE`**:只在当前目标内部使用这个库。依赖此目标的其他目标**不会**自动链接这个库。
- **`PUBLIC`**:当前目标使用这个库,并且依赖此目标的其他目标**也会**自动链接这个库。
- **`INTERFACE`**:当前目标**不**使用这个库,但依赖此目标的其他目标**会**自动链接这个库。(通常用于头文件中包含了需要链接的库的情况)
- ```
<library>
链接库文件
link_libraries()
target_link_libraries() 是一个非常重要的 CMake 命令,它用于将目标文件与库文件进行链接。
link_directories(${CMAKE_CURRENT_LIST_DIR}) 指定库路径
变量操作
1 | set(变量名 ${变量名1} ¥{变量名2} ...) |
宏相关操作
1 | add_definitions(-DDEBUG) |
嵌套 CMake
下面给一个最清晰、最实用的 CMake 嵌套(多层 CMakeLists)教程,
就是一个项目包含多个子模块,每个模块有自己的 CMakeLists.txt,主项目通过:
1 | add_subdirectory(subdir) |
把子目录的目标(库/可执行文件)纳入整个构建系统。
常见用途:
- 大项目拆成模块(network、base、util、server…)
- 多个独立编译的库
- 测试目录(tests/)
- 示例目录(examples/)
🧱 项目结构例子
比如你现在的 muduo-core 项目可以是:
1 | project/ |
🧩 顶层 CMakeLists.txt 写法(主入口)
1 | cmake_minimum_required(VERSION 3.10) |
很干净,就是把各子模块导入进来。
📦 src/CMakeLists.txt(模块集合)
1 | # src/CMakeLists.txt |
🧱 base/CMakeLists.txt(创建一个库)
1 | add_library(base |
🌐 net/CMakeLists.txt(依赖其它子模块)
1 | add_library(net |
🔧 util/CMakeLists.txt
1 | add_library(util |
▶ examples/CMakeLists.txt(示例程序)
1 | add_subdirectory(echo) |
🎤 examples/echo/CMakeLists.txt
1 | add_executable(echo main.cpp) |
⚙️ CMake 如何自动处理嵌套依赖?
比如:
echo依赖netnet依赖basebase无依赖
CMake 自动会根据依赖关系排序编译顺序。
这就是嵌套 CMake 的最大优点:可维护、清晰、模块化。