少女祈祷中...

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 设置一个名为 PROJECT_NAME 的变量,其值为 "MyAwesomeProject"
set(PROJECT_NAME "MyAwesomeProject")

# 打印变量的值
message("Project Name: ${PROJECT_NAME}")
# 输出: Project Name: MyAwesomeProject

# 设置一个列表变量
set(SOURCE_FILES main.cpp utils.cpp)

# 打印列表中的所有元素
message("Source Files: ${SOURCE_FILES}")
# 输出: Source Files: main.cpp utils.cpp

# 向列表中添加新元素
list(APPEND SOURCE_FILES "another_file.cpp")
message("Updated Source Files: ${SOURCE_FILES}")
# 输出: Updated Source Files: main.cpp utils.cpp another_file.cpp

aux_source_directory()

aux_source_directory() 是一个辅助命令,它的核心作用是:

自动查找指定目录下的所有源文件(默认是 .c.cpp 等),并将这些文件的路径列表存储到一个变量中。

基本用法: aux_source_directory(

)

  • <dir>: 要搜索的目录路径。可以是相对路径(相对于当前 CMakeLists.txt 文件所在的目录)或绝对路径。
  • <variable>: 用于存储找到的源文件列表的变量名。

举例

项目结构:

1
2
3
4
5
6
7
8
MyProject/
├── CMakeLists.txt
└── src/
├── main.cpp
├── utils.cpp
└── math/
├── add.cpp
└── multiply.cpp

cmake

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
cmake_minimum_required(VERSION 3.10)
project(MyProject)

# 手动列出 src 目录下的源文件
set(SOURCE_FILES
src/main.cpp
src/utils.cpp
src/math/add.cpp
src/math/multiply.cpp
)

add_executable(my_app ${SOURCE_FILES})

# 简单写法
# ----------------------------------------------------

cmake_minimum_required(VERSION 3.10)
project(MyProject)

# 自动查找 src 目录下的所有源文件,并将列表存入 SRC_FILES 变量
aux_source_directory(src SRC_FILES)

# 打印找到的文件列表,方便调试
message("Found source files: ${SRC_FILES}")

add_executable(my_app ${SRC_FILES})

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>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    : 这是

    作用域关键字

    ,用于控制依赖的传递性。

    - **`PRIVATE`**:只在当前目标内部使用这个库。依赖此目标的其他目标**不会**自动链接这个库。
    - **`PUBLIC`**:当前目标使用这个库,并且依赖此目标的其他目标**也会**自动链接这个库。
    - **`INTERFACE`**:当前目标**不**使用这个库,但依赖此目标的其他目标**会**自动链接这个库。(通常用于头文件中包含了需要链接的库的情况)

    - ```
    <library>
    : 要链接的库的名称。这个名称可以是: - 你项目中其他 `add_library` 定义的目标名称(如 `calc`)。 - 系统库的名称(如 `pthread`)。 - 一个完整的库文件路径(不推荐,但有时必要)。

链接库文件

link_libraries()

target_link_libraries() 是一个非常重要的 CMake 命令,它用于将目标文件与库文件进行链接

link_directories(${CMAKE_CURRENT_LIST_DIR}) 指定库路径

变量操作

1
set(变量名 ${变量名1} ¥{变量名2} ...)

宏相关操作

1
2
3
4
5
add_definitions(-DDEBUG) 

#ifdef DEBUG
std::cout << "this is hong\n"; 执行这部分
#endif

嵌套 CMake

下面给一个最清晰、最实用的 CMake 嵌套(多层 CMakeLists)教程

就是一个项目包含多个子模块,每个模块有自己的 CMakeLists.txt,主项目通过:

1
add_subdirectory(subdir)

把子目录的目标(库/可执行文件)纳入整个构建系统。

常见用途:

  • 大项目拆成模块(network、base、util、server…)
  • 多个独立编译的库
  • 测试目录(tests/)
  • 示例目录(examples/)

🧱 项目结构例子

比如你现在的 muduo-core 项目可以是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
project/
├── CMakeLists.txt # 顶级
├── src/
│ ├── CMakeLists.txt
│ ├── net/
│ │ ├── CMakeLists.txt
│ │ ├── TcpServer.cpp
│ │ └── TcpServer.h
│ ├── base/
│ │ ├── CMakeLists.txt
│ │ ├── Timestamp.cpp
│ │ └── Timestamp.h
│ └── util/
│ ├── CMakeLists.txt
│ └── Log.cpp
└── examples/
├── CMakeLists.txt
├── echo/
│ ├── CMakeLists.txt
│ └── main.cpp

🧩 顶层 CMakeLists.txt 写法(主入口)

1
2
3
4
5
6
7
8
9
10
cmake_minimum_required(VERSION 3.10)
project(muduo-core)

set(CMAKE_CXX_STANDARD 17)

# 添加 src 目录
add_subdirectory(src)

# 添加 examples 目录
add_subdirectory(examples)

很干净,就是把各子模块导入进来。

📦 src/CMakeLists.txt(模块集合)

1
2
3
4
5
# src/CMakeLists.txt

add_subdirectory(base)
add_subdirectory(net)
add_subdirectory(util)

🧱 base/CMakeLists.txt(创建一个库)

1
2
3
4
5
add_library(base
Timestamp.cpp
)

target_include_directories(base PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

🌐 net/CMakeLists.txt(依赖其它子模块)

1
2
3
4
5
6
7
8
add_library(net
TcpServer.cpp
)

# 依赖 base 库
target_link_libraries(net PUBLIC base)

target_include_directories(net PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

🔧 util/CMakeLists.txt

1
2
3
4
5
add_library(util
Log.cpp
)

target_include_directories(util PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

▶ examples/CMakeLists.txt(示例程序)

1
add_subdirectory(echo)

🎤 examples/echo/CMakeLists.txt

1
2
3
4
add_executable(echo main.cpp)

# 链接到 net 和 base
target_link_libraries(echo PRIVATE net util base)

⚙️ CMake 如何自动处理嵌套依赖?

比如:

  • echo 依赖 net
  • net 依赖 base
  • base 无依赖

CMake 自动会根据依赖关系排序编译顺序。

这就是嵌套 CMake 的最大优点:可维护、清晰、模块化