好的,我们进入 第四课:项目结构与多个源文件、头文件管理。
本课重点是:项目拆分、多个源码文件、头文件路径设置、模块化管理。
🧱 本课目标
-
项目中添加多个
.cpp文件和.h文件 -
使用
target_include_directories()设置头文件搜索路径 -
初步理解模块化(为后面学习库的构建做准备)
🧩 示例项目结构
我们创建一个更复杂一点的小项目,结构如下:
multi_file_project/
├── CMakeLists.txt
├── main.cpp
├── math/
│ ├── add.h
│ └── add.cpp
🧮 功能:实现一个加法函数,在 main.cpp 中调用。
📄 1. 源码文件内容
✅ main.cpp
#include <iostream>
#include "add.h"
int main() {
int result = add(3, 4);
std::cout << "3 + 4 = " << result << std::endl;
return 0;
}
✅ math/add.h
#pragma once
int add(int a, int b);
✅ math/add.cpp
#include "add.h"
int add(int a, int b) {
return a + b;
}
📘 2. CMakeLists.txt(多文件版本)
cmake_minimum_required(VERSION 3.10)
project(MultiFileProject VERSION 1.0 LANGUAGES CXX)
add_executable(my_app
main.cpp
math/add.cpp
)
# 设置 C++17 标准
target_compile_features(my_app PRIVATE cxx_std_17)
# 添加头文件目录
target_include_directories(my_app PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/math
)
命令讲解:
-
add_executable(my_app ...):将main.cpp和add.cpp都编译进去 -
target_include_directories(...):告诉编译器头文件在哪找(如add.h在math/文件夹下)
✅ 实践流程(命令行版)
# 创建并进入构建目录
mkdir build
cd build
# 生成工程(以 VS2022 为例)
cmake .. -G "Visual Studio 17 2022"
# 编译(Release 模式)
cmake --build . --config Release
# 运行(路径为 ./Release/my_app.exe)
./Release/my_app.exe
预期输出:
3 + 4 = 7
🧠 小贴士:include 头文件路径问题
如果你没写 target_include_directories(),CMake 默认只会去 main.cpp 所在目录找头文件。这就会导致:
#include "add.h" // 报错,找不到头文件
所以一定要用:
target_include_directories(my_app PRIVATE math)
才能告诉它去 math/ 子目录找。
🧪 小测验(加深理解)
-
target_include_directories()是干什么用的?✅ 设置头文件搜索路径。
-
如果我们忘记在
add_executable()中写math/add.cpp会怎样?❌ 链接时报错,提示找不到
add函数。 -
#pragma once是什么意思?✅ 防止头文件被重复包含,等效于
#ifndef/#define/#endif。
上面两个 target_include_directories 写法看起来很像,但其实有一些关键差别,我们来详细解释一下:
✅ 两种target_include_directories写法对比
✅ 写法一(相对路径):
target_include_directories(my_app PRIVATE math)
这表示:
在编译器中添加
-I<math>,也就是从**当前构建目录(build 目录)**起找math/子目录。
问题是:
-
math是相对路径,它是相对于“编译目录”而不是“源码目录”。 -
所以,如果你在 build/ 目录 中执行
cmake ..,math指的是build/math,但这个目录根本不存在!
👉 会导致编译器找不到头文件,出现 add.h: No such file or directory 错误。
✅ 写法二(绝对路径推荐写法):
target_include_directories(my_app PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/math
)
这表示:
在编译器中添加
-I<完整路径到源码的 math>,即:-I D:/your_project/multi_file_project/math。
这是 绝对路径,由 CMake 自动拼出项目中 math/ 文件夹在磁盘上的实际路径,始终有效。
🔍 总结对比表
| 写法 | 解释 | 是否推荐 | 原因 |
|---|---|---|---|
math | 相对路径,可能出错 | ❌ 不推荐 | 相对的是构建目录,容易出错 |
${CMAKE_CURRENT_SOURCE_DIR}/math | 绝对路径 | ✅ 推荐 | 始终正确指向源码中的目录 |
🧠 延伸知识:还有哪些变量可以用?
| CMake 变量 | 含义 |
|---|---|
${CMAKE_CURRENT_SOURCE_DIR} | 当前 CMakeLists.txt 所在目录(源码路径) |
${CMAKE_CURRENT_BINARY_DIR} | 构建目录中对应的子目录(build 路径) |
${PROJECT_SOURCE_DIR} | 顶层源码目录 |
${PROJECT_BINARY_DIR} | 顶层构建目录 |
✅ 实践建议
以后凡是涉及路径(不论是 include、库、脚本),统一用绝对路径(即加上 CMAKE_CURRENT_SOURCE_DIR)最安全稳定。
你只在写临时项目或手工编译时才会考虑用相对路径。
如果你愿意,我可以展示一个例子:错误写法 vs 正确写法对比演示,让你更加直观理解。是否需要?还是我们继续进入下一课?
⏮️ 上一课回顾:【CMake基础入门】第三课:构建系统与构建类型详解
⏭️ 下一课预告:【CMake基础入门】第五课:拆分模块与使用 add_subdirectory() 构建子目录项目
我们将学会:
-
如何把模块单独建一个子项目(比如 math 模块变成子库)
-
如何将其用
add_subdirectory()引入主工程
690

被折叠的 条评论
为什么被折叠?



