【CMake基础入门教程】第四课:项目结构与多个源文件、头文件管理

好的,我们进入 第四课:项目结构与多个源文件、头文件管理

本课重点是:项目拆分、多个源码文件、头文件路径设置、模块化管理。


🧱 本课目标

  1. 项目中添加多个 .cpp 文件和 .h 文件

  2. 使用 target_include_directories() 设置头文件搜索路径

  3. 初步理解模块化(为后面学习库的构建做准备)


🧩 示例项目结构

我们创建一个更复杂一点的小项目,结构如下:

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.cppadd.cpp 都编译进去

  • target_include_directories(...):告诉编译器头文件在哪找(如 add.hmath/ 文件夹下)


✅ 实践流程(命令行版)

# 创建并进入构建目录
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/ 子目录找。


🧪 小测验(加深理解)

  1. target_include_directories() 是干什么用的?

    ✅ 设置头文件搜索路径。

  2. 如果我们忘记在 add_executable() 中写 math/add.cpp 会怎样?

    ❌ 链接时报错,提示找不到 add 函数。

  3. #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() 引入主工程


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奇异果冻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值