【0基础嵌入式学习日志】Day05:Makefile 自动化、通配符、模式规则与增量编译
一、前言
今天继续进行嵌入式 C 语言基础学习。前面几天已经完成了 C 工程结构、结构体、故障码、函数封装、多文件拆分、.h/.c配合以及.c → .o → 可执行文件的分步编译流程。
Day04 中,Makefile 已经可以将多个.c文件分别编译成.o文件,再链接生成最终可执行程序:
src/main.c → build/main.o src/system.c → build/system.o src/sensor.c → build/sensor.o src/fault.c → build/fault.o build/main.o + build/system.o + build/sensor.o + build/fault.o → build/day04_test但是 Day04 的 Makefile 仍然存在一个问题:每个.o文件和对应的编译规则都需要手动写出来。随着工程文件数量增加,这种写法会越来越麻烦。
因此,Day05 的重点是学习 Makefile 的自动化写法,包括:
wildcard patsubst 模式规则 自动变量 $< 和 $@ 增量编译目标是让 Makefile 自动查找src目录下所有.c文件,并自动生成对应的.o文件。
二、Day05 学习目标
本次 Day05 主要学习以下内容:
- 理解为什么要进一步优化 Makefile;
- 学会使用
wildcard自动查找.c文件; - 学会使用
patsubst自动生成.o文件列表; - 理解模式规则
build/%.o: src/%.c; - 理解自动变量
$<和$@的含义; - 验证 Makefile 的增量编译机制;
- 理解修改单个
.c文件后只重新编译对应.o文件的过程。
三、Day05 工程结构
Day05 工程是在 Day04 的基础上复制并修改得到的,整体结构如下:
day05 ├── Makefile ├── include │ ├── fault_code.h │ ├── fault.h │ ├── sensor.h │ ├── system.h │ └── system_type.h ├── src │ ├── fault.c │ ├── main.c │ ├── sensor.c │ └── system.c └── build ├── fault.o ├── main.o ├── sensor.o ├── system.o └── day05_test其中:
include:存放头文件;src:存放源文件;build:存放编译生成的.o文件和可执行文件;Makefile:管理自动化编译、运行和清理;README.md:记录项目说明。
需要注意的是,build目录中的.o文件和day05_test是本地编译产物,一般不需要上传到 GitHub。
四、为什么要优化 Day04 的 Makefile?
Day04 的 Makefile 中手动写出了每一个目标文件:
OBJS = build/main.o build/system.o build/sensor.o build/fault.o并且每一个.c文件都要单独写一条编译规则:
build/main.o: src/main.c $(CC) $(CFLAGS) -c src/main.c -o build/main.o build/system.o: src/system.c $(CC) $(CFLAGS) -c src/system.c -o build/system.o build/sensor.o: src/sensor.c $(CC) $(CFLAGS) -c src/sensor.c -o build/sensor.o build/fault.o: src/fault.c $(CC) $(CFLAGS) -c src/fault.c -o build/fault.o这种方式虽然清楚,但是不够灵活。
如果后面新增一个源文件,例如:
src/uart.c就需要手动修改 Makefile,增加:
build/uart.o以及对应的编译规则。
真实嵌入式工程中,.c文件可能很多,如果每个文件都手动维护,效率会很低,也容易出错。
因此,Day05 使用更加自动化的 Makefile 写法,让它自动完成:
自动查找 src 目录下所有 .c 文件 自动生成 build 目录下对应的 .o 文件 使用一条模式规则完成所有 .c 文件的编译五、Day05 Makefile 内容
Day05 的 Makefile 内容如下:
CC = gcc CFLAGS = -Wall -Wextra -Iinclude TARGET = build/day05_test SRCS = $(wildcard src/*.c) OBJS = $(patsubst src/%.c, build/%.o, $(SRCS)) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(OBJS) -o $(TARGET) build/%.o: src/%.c $(CC) $(CFLAGS) -c $< -o $@ run: $(TARGET) ./$(TARGET) clean: rm -f build/*.o $(TARGET)这里和 Day04 最大的区别是下面三部分:
SRCS = $(wildcard src/*.c) OBJS = $(patsubst src/%.c, build/%.o, $(SRCS)) build/%.o: src/%.c $(CC) $(CFLAGS) -c $< -o $@这几句是 Day05 的核心。
六、Makefile 逐句理解
1. 指定编译器
CC = gccCC表示 C Compiler,也就是 C 语言编译器。
后面使用:
$(CC)就等价于:
gcc这样写的好处是:如果以后想换成其他编译器,只需要修改CC的值。
2. 指定编译参数
CFLAGS = -Wall -Wextra -Iinclude其中:
-Wall:开启常见警告;-Wextra:开启更多警告;-Iinclude:告诉 GCC 到include目录查找头文件。
因为代码中包含了自己写的头文件:
#include"system.h"#include"sensor.h"#include"fault.h"这些头文件都放在include目录下,所以需要使用:
-Iinclude3. 指定最终可执行文件
TARGET = build/day05_test这表示最终生成的可执行文件是:
build/day05_test运行时可以使用:
./build/day05_test七、wildcard:自动查找源文件
SRCS = $(wildcard src/*.c)wildcard的作用是自动查找符合条件的文件。
这里:
$(wildcard src/*.c)表示查找src目录下所有.c文件。
如果src目录中有:
src/fault.c src/main.c src/sensor.c src/system.c那么:
SRCS = $(wildcard src/*.c)最终相当于:
SRCS = src/fault.c src/main.c src/sensor.c src/system.c这样以后如果新增一个:
src/uart.cMakefile 会自动找到它,不需要手动修改SRCS。
八、patsubst:自动生成目标文件列表
OBJS = $(patsubst src/%.c, build/%.o, $(SRCS))patsubst是模式替换函数。
它的作用是把SRCS中的.c文件路径转换成对应的.o文件路径。
例如:
src/main.c → build/main.o src/system.c → build/system.o src/sensor.c → build/sensor.o src/fault.c → build/fault.o也就是说:
OBJS = $(patsubst src/%.c, build/%.o, $(SRCS))最终等价于:
OBJS = build/fault.o build/main.o build/sensor.o build/system.o这样就不需要手动写每一个.o文件了。
九、模式规则:一条规则编译所有 .c 文件
Day04 中每个.c文件都需要单独写规则。
Day05 中使用一条模式规则:
build/%.o: src/%.c $(CC) $(CFLAGS) -c $< -o $@这句表示:
所有 build/xxx.o 都可以由 src/xxx.c 编译得到例如:
build/main.o 由 src/main.c 生成 build/system.o 由 src/system.c 生成 build/sensor.o 由 src/sensor.c 生成 build/fault.o 由 src/fault.c 生成这里的%可以理解为匹配相同的文件名。
例如:
build/sensor.o: src/sensor.c其中%就对应sensor。
十、自动变量 $< 和 $@
在模式规则中使用了两个自动变量:
$< $@它们的含义是:
$< 表示当前规则中的第一个依赖文件 $@ 表示当前规则中的目标文件例如当前规则是:
build/sensor.o: src/sensor.c那么:
$< = src/sensor.c $@ = build/sensor.o所以:
$(CC) $(CFLAGS) -c $< -o $@就等价于:
gcc-Wall-Wextra-Iinclude-csrc/sensor.c-obuild/sensor.o这样一条规则就可以适用于所有.c → .o的编译过程。
十一、生成最终程序
$(TARGET): $(OBJS) $(CC) $(OBJS) -o $(TARGET)这句表示:
要生成 build/day05_test 必须先生成所有 .o 文件展开后大概等价于:
gcc build/fault.o build/main.o build/sensor.o build/system.o-obuild/day05_test这一步是链接过程,也就是把多个.o文件链接成最终可执行程序。
十二、运行与清理
1. 运行程序
run: $(TARGET) ./$(TARGET)执行:
makerun等价于:
./build/day05_test2. 清理编译产物
clean: rm -f build/*.o $(TARGET)执行:
makeclean会删除:
build/*.o build/day05_test也就是删除所有.o目标文件和最终可执行程序。
十三、编译与运行
进入 Day05 目录:
cd/root/Embedded_14Days/day05清理旧编译产物:
makeclean编译:
make查看build目录:
lsbuild可以看到:
day05_test fault.o main.o sensor.o system.o运行程序:
makerun运行结果如下:
LED state:0Voltage:9.50V Current:2.50A temperature:72.00C Fault code: 0x0007 Fault: Low voltage Fault: Over current Fault: Over temperature说明 Makefile 已经可以自动完成:
查找源文件 生成目标文件 链接可执行程序 运行程序十四、增量编译验证
Day05 另一个重点是验证增量编译。
首先,在没有修改任何文件的情况下,再次执行:
make终端输出:
make: Nothing to bedonefor'all'.这说明当前所有目标文件都是最新的,不需要重新编译。
然后修改src/sensor.c中的温度值:
sys->temperature=72.0f;改成:
sys->temperature=75.0f;保存后再次执行:
make此时终端只重新编译了:
gcc-Wall-Wextra-Iinclude-csrc/sensor.c-obuild/sensor.o然后重新链接:
gcc build/fault.o build/main.o build/sensor.o build/system.o-obuild/day05_test这说明 Makefile 判断出只有sensor.c被修改,所以只重新生成了:
build/sensor.o而没有重新编译:
main.c system.c fault.c这就是增量编译。
十五、修改后的运行结果
再次执行:
makerun运行结果如下:
LED state:0Voltage:9.50V Current:2.50A temperature:75.00C Fault code: 0x0007 Fault: Low voltage Fault: Over current Fault: Over temperature可以看到温度已经从72.00 C变成了75.00 C,说明修改后的sensor.c已经重新编译并生效。
十六、Day04 和 Day05 的区别
Day04 的 Makefile 是手动列出目标文件和规则:
OBJS = build/main.o build/system.o build/sensor.o build/fault.o并且每个.c文件都要单独写一条规则。
Day05 的 Makefile 使用自动化写法:
SRCS = $(wildcard src/*.c) OBJS = $(patsubst src/%.c, build/%.o, $(SRCS)) build/%.o: src/%.c $(CC) $(CFLAGS) -c $< -o $@也就是说:
Day04:手动列出每个 .o 文件和编译规则 Day05:自动查找 .c 文件,自动生成 .o 文件,并用一条模式规则统一编译Day05 的 Makefile 更适合后续扩展工程。
十七、遇到的问题和解决方法
1. 目录路径不能直接当命令执行
学习过程中曾经直接输入:
/root/Embedded_14Days/day05终端提示:
Is a directory原因是目录路径本身不是命令,不能直接执行。
正确进入目录的方式是:
cd/root/Embedded_14Days/day052. git add 的路径要看当前所在目录
在上传 GitHub 时,如果当前已经在day05目录中,再执行:
gitaddday05Git 会去找:
day05/day05自然找不到。
更清楚的做法是先回到总目录:
cd/root/Embedded_14Days然后执行:
gitaddday05这样路径就不会出错。
十八、今日总结
通过 Day05 的学习,主要掌握了以下内容:
- 学会了使用
wildcard自动查找src目录下所有.c文件; - 学会了使用
patsubst自动将.c文件列表转换成.o文件列表; - 理解了模式规则
build/%.o: src/%.c; - 理解了自动变量
$<和$@的作用; - 学会了使用一条规则编译多个
.c文件; - 验证了 Makefile 的增量编译机制;
- 理解了修改单个
.c文件后,只需要重新编译对应.o文件; - 进一步理解了真实 C 工程中的自动化构建流程。
Day05 的核心可以总结为一句话:
Makefile 自动查找源文件, 自动生成目标文件列表, 使用模式规则统一编译, 并支持增量编译。这一步对于后续学习嵌入式工程、驱动模块拆分、复杂 Makefile 和交叉编译非常重要。
十九、项目源码
本次 Day05 学习代码已上传至 GitHub:
https://github.com/jdai10590-afk/Embedded-C-Learning-Projects/tree/main/day05
【0基础嵌入式学习日志】Day06:头文件依赖追踪、.d 文件与完整增量编译
一、前言
今天继续进行嵌入式 C 语言基础学习。前面几天已经逐步完成了 C 工程结构、函数封装、多文件拆分、Makefile 自动化、.c → .o → 可执行文件的分步编译流程,以及通过wildcard、patsubst和模式规则实现自动化编译。
Day05 中,Makefile 已经可以自动完成:
自动查找 src 目录下所有 .c 文件 自动生成 build 目录下对应的 .o 文件 使用一条模式规则编译所有 .c 文件 修改某个 .c 文件后,只重新编译对应的 .o 文件但是 Day05 还存在一个问题:它主要追踪.c文件的变化。如果修改的是.h头文件,Makefile 不一定知道哪些.o文件需要重新编译。
因此,Day06 的重点是学习头文件依赖追踪,也就是让 Makefile 能够知道:
某个 .o 文件不仅依赖对应的 .c 文件, 还依赖它所包含的 .h 头文件。本次学习通过 GCC 的-MMD -MP参数自动生成.d依赖文件,并在 Makefile 中引入这些.d文件,从而实现更完整的增量编译。
二、Day06 学习目标
本次 Day06 主要学习以下内容:
- 理解为什么
.h文件变化也会影响编译; - 理解
.d依赖文件的作用; - 学会使用
-MMD -MP自动生成头文件依赖信息; - 学会通过
DEPS自动生成.d文件列表; - 学会使用
-include $(DEPS)将依赖文件引入 Makefile; - 验证修改头文件后,相关
.o文件能够自动重新编译; - 进一步理解真实 C 工程中的完整增量编译机制。
三、Day06 工程结构
Day06 工程是在 Day05 基础上复制并修改得到的,工程结构如下:
day06 ├── Makefile ├── include │ ├── fault_code.h │ ├── fault.h │ ├── sensor.h │ ├── system.h │ └── system_type.h ├── src │ ├── fault.c │ ├── main.c │ ├── sensor.c │ └── system.c └── build ├── fault.d ├── fault.o ├── main.d ├── main.o ├── sensor.d ├── sensor.o ├── system.d ├── system.o └── day06_test其中:
include:存放头文件;src:存放源文件;build:存放.o目标文件、.d依赖文件和最终可执行程序;Makefile:管理编译、链接、运行和清理过程;README.md:记录项目说明。
相比 Day05,Day06 的build目录中多出了.d文件,例如:
fault.d main.d sensor.d system.d这些.d文件就是今天学习的重点。
四、为什么需要头文件依赖追踪?
在 C 工程中,.h头文件通常会存放:
宏定义 结构体定义 函数声明 枚举类型 寄存器地址 配置参数 故障码定义例如本项目中的fault_code.h用来定义故障码:
#ifndefFAULT_CODE_H#defineFAULT_CODE_H#defineFAULT_NONE0x0000#defineFAULT_LOW_VOLTAGE0x0001#defineFAULT_OVER_CURRENT0x0002#defineFAULT_OVER_TEMP0x0004#defineFAULT_SENSOR_ERROR0x0008// sensor fault#endif这个头文件会被多个.c文件间接或直接使用。
例如:
system.c 使用 fault_code.h 中的 FAULT_NONE、FAULT_LOW_VOLTAGE 等宏 fault.c 使用 fault_code.h 中的故障码宏定义如果修改了fault_code.h,那么依赖它的.c文件应该重新编译。
但是 Day05 的规则主要是:
build/%.o: src/%.c $(CC) $(CFLAGS) -c $< -o $@这条规则只告诉 Makefile:
build/xxx.o 依赖 src/xxx.c并没有告诉 Makefile:
build/system.o 还依赖 include/system.h、include/system_type.h、include/fault_code.h所以 Day06 要解决的问题就是:
让 Makefile 自动知道每个 .o 文件到底依赖哪些 .c 和 .h 文件。五、.d 文件是什么?
.d文件是依赖文件。
它的作用是记录:
某个 .o 文件依赖哪些 .c 文件和 .h 文件。例如,编译system.c后会生成:
build/system.o build/system.d其中system.o是目标文件,system.d是依赖文件。
查看system.d:
catbuild/system.d可以看到类似内容:
build/system.o: src/system.c include/system.h include/system_type.h \ include/fault_code.h include/system.h: include/system_type.h: include/fault_code.h:这表示:
build/system.o 依赖 src/system.c build/system.o 依赖 include/system.h build/system.o 依赖 include/system_type.h build/system.o 依赖 include/fault_code.h因此,如果这些文件中的任何一个发生变化,Makefile 就知道build/system.o需要重新编译。
这就是.d文件的作用。
六、Day06 Makefile 内容
Day06 的 Makefile 内容如下:
CC = gcc CFLAGS = -Wall -Wextra -Iinclude DEPFLAGS = -MMD -MP TARGET = build/day06_test SRCS = $(wildcard src/*.c) OBJS = $(patsubst src/%.c, build/%.o, $(SRCS)) DEPS = $(patsubst src/%.c, build/%.d, $(SRCS)) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(OBJS) -o $(TARGET) build/%.o: src/%.c $(CC) $(CFLAGS) $(DEPFLAGS) -c $< -o $@ run: $(TARGET) ./$(TARGET) clean: rm -f build/*.o build/*.d $(TARGET) -include $(DEPS)相比 Day05,Day06 主要新增了三部分:
DEPFLAGS = -MMD -MP DEPS = $(patsubst src/%.c, build/%.d, $(SRCS)) -include $(DEPS)并且编译规则中增加了:
$(DEPFLAGS)七、Makefile 关键语句解释
1. 编译器设置
CC = gccCC表示 C Compiler,也就是 C 编译器。
后面写:
$(CC)就等价于:
gcc2. 编译参数
CFLAGS = -Wall -Wextra -Iinclude其中:
-Wall:开启常见警告;-Wextra:开启更多警告;-Iinclude:告诉 GCC 到include目录查找头文件。
因为本项目的头文件都放在:
day06/include所以需要通过:
-Iinclude指定头文件搜索路径。
3. 依赖生成参数
DEPFLAGS = -MMD -MP这是 Day06 的新增内容。
其中:
-MMD:让 GCC 自动生成项目头文件依赖信息 -MP:为头文件生成伪目标,避免头文件被删除后 Makefile 报错简单理解:
-MMD -MP 的作用就是让 GCC 在编译 .c 文件时,同时生成 .d 依赖文件。例如编译:
gcc-Wall-Wextra-Iinclude-MMD-MP-csrc/system.c-obuild/system.o会同时生成:
build/system.o build/system.d4. 最终目标文件
TARGET = build/day06_test表示最终生成的可执行程序是:
build/day06_test5. 自动查找源文件
SRCS = $(wildcard src/*.c)wildcard用于自动查找src目录下所有.c文件。
例如:
src/fault.c src/main.c src/sensor.c src/system.c都会被自动加入SRCS。
6. 自动生成 .o 文件列表
OBJS = $(patsubst src/%.c, build/%.o, $(SRCS))这句会把.c文件路径转换成.o文件路径。
例如:
src/main.c -> build/main.o src/system.c -> build/system.o src/sensor.c -> build/sensor.o src/fault.c -> build/fault.o最终OBJS就是:
build/fault.o build/main.o build/sensor.o build/system.o7. 自动生成 .d 文件列表
DEPS = $(patsubst src/%.c, build/%.d, $(SRCS))这句和OBJS很像。
区别是:
OBJS 生成 .o 文件列表 DEPS 生成 .d 文件列表例如:
src/main.c -> build/main.d src/system.c -> build/system.d src/sensor.c -> build/sensor.d src/fault.c -> build/fault.d最终DEPS包含:
build/fault.d build/main.d build/sensor.d build/system.d8. 编译目标
all: $(TARGET)当输入:
make时,默认会执行第一个目标all。
这句表示:
make 的目标是生成 build/day06_test。9. 链接最终程序
$(TARGET): $(OBJS) $(CC) $(OBJS) -o $(TARGET)这表示:
要生成 build/day06_test,必须先生成所有 .o 文件。展开后大概等价于:
gcc build/fault.o build/main.o build/sensor.o build/system.o-obuild/day06_test这一步叫链接,也就是把多个.o文件链接成最终可执行程序。
10. 模式规则生成 .o 和 .d
build/%.o: src/%.c $(CC) $(CFLAGS) $(DEPFLAGS) -c $< -o $@这句表示:
所有 build/xxx.o 都可以由 src/xxx.c 编译得到。例如:
build/system.o 由 src/system.c 编译得到 build/fault.o 由 src/fault.c 编译得到其中:
$< 表示输入文件,也就是 src/xxx.c $@ 表示输出目标,也就是 build/xxx.o因为加入了:
$(DEPFLAGS)所以每次编译.c文件时,不仅生成.o,还会生成.d。
11. 运行程序
run: $(TARGET) ./$(TARGET)执行:
makerun会运行:
./build/day06_test12. 清理编译产物
clean: rm -f build/*.o build/*.d $(TARGET)执行:
makeclean会删除:
build/*.o build/*.d build/day06_test也就是删除目标文件、依赖文件和最终可执行程序。
13. 引入依赖文件
-include $(DEPS)这是 Day06 最关键的一句。
它的作用是:
把所有 .d 文件包含进 Makefile, 让 Makefile 知道每个 .o 文件还依赖哪些 .h 文件。前面的-表示:
如果 .d 文件暂时不存在,也不要报错。因为第一次执行make时,.d文件还没有生成。如果直接写:
include $(DEPS)第一次可能会因为找不到.d文件而报错。
所以更稳妥的写法是:
-include $(DEPS)八、编译与运行
进入 Day06 目录:
cd/root/Embedded_14Days/day06清理旧文件:
makeclean编译:
make查看build目录:
lsbuild可以看到:
day06_test fault.d fault.o main.d main.o sensor.d sensor.o system.d system.o运行程序:
makerun运行结果如下:
LED state:0Voltage:9.50V Current:2.50A temperature:75.00C Fault code: 0x0007 Fault: Low voltage Fault: Over current Fault: Over temperature这说明程序编译和运行都正常。
九、查看 .d 文件内容
执行:
catbuild/system.d可以看到类似:
build/system.o: src/system.c include/system.h include/system_type.h \ include/fault_code.h include/system.h: include/system_type.h: include/fault_code.h:这一段说明:
build/system.o 依赖 src/system.c build/system.o 依赖 include/system.h build/system.o 依赖 include/system_type.h build/system.o 依赖 include/fault_code.h因此,如果修改include/fault_code.h,Makefile 就知道system.o需要重新编译。
后面这些内容:
include/system.h: include/system_type.h: include/fault_code.h:是-MP自动生成的伪目标,主要用于避免头文件被删除后 Makefile 报错。
十、头文件依赖验证
为了验证头文件依赖是否生效,修改:
day06/include/fault_code.h将:
#defineFAULT_SENSOR_ERROR0x0008改成:
#defineFAULT_SENSOR_ERROR0x0008// sensor fault保存后,再执行:
make终端输出中可以看到:
gcc-Wall-Wextra-Iinclude-MMD-MP-csrc/fault.c-obuild/fault.o gcc-Wall-Wextra-Iinclude-MMD-MP-csrc/system.c-obuild/system.o gcc build/fault.o build/main.o build/sensor.o build/system.o-obuild/day06_test这说明修改fault_code.h后,Makefile 自动判断出:
fault.o 依赖 fault_code.h system.o 依赖 fault_code.h所以重新编译了:
src/fault.c -> build/fault.o src/system.c -> build/system.o没有重新编译:
src/main.c src/sensor.c这说明头文件依赖追踪已经生效。
十一、Day05 和 Day06 的区别
Day05 主要解决的是.c文件变化:
修改 sensor.c ↓ 重新编译 sensor.o ↓ 重新链接 day05_testDay06 进一步解决的是.h文件变化:
修改 fault_code.h ↓ Makefile 根据 .d 文件判断哪些 .o 依赖它 ↓ 重新编译 fault.o 和 system.o ↓ 重新链接 day06_test也就是说:
Day05:支持源文件级别的增量编译 Day06:支持头文件依赖级别的增量编译Day06 更接近真实 C 工程和嵌入式工程中的构建方式。
十二、遇到的问题和解决方法
1. -MD 和 -MMD 的区别
一开始编译命令中使用过:
-MD-MP后来改成:
-MMD-MP两者区别是:
-MD:会记录系统头文件和项目头文件 -MMD:主要记录项目头文件,不记录系统标准库头文件例如<stdio.h>这类系统头文件,一般不需要在项目依赖文件中追踪。
所以本项目最终使用:
DEPFLAGS = -MMD -MP这样更加适合当前工程。
2. .d 文件第一次不存在怎么办?
第一次执行make时,.d文件还没有生成。
如果直接写:
include $(DEPS)可能会因为找不到.d文件而报错。
因此使用:
-include $(DEPS)前面的-表示:即使文件暂时不存在,也不要报错。
3. build 文件夹中的 .o 和 .d 不需要上传 GitHub
build目录中的文件属于编译产物,例如:
fault.o main.o sensor.o system.o fault.d main.d sensor.d system.d day06_test这些文件可以通过源码和 Makefile 重新生成,一般不需要上传 GitHub。
GitHub 上主要保留:
Makefile README.md include/*.h src/*.c十三、今日总结
通过 Day06 的学习,主要掌握了以下内容:
- 理解了
.h头文件变化也会影响.o文件; - 理解了
.d文件用于记录目标文件依赖关系; - 学会了使用
-MMD -MP自动生成.d文件; - 学会了通过
DEPS自动生成依赖文件列表; - 学会了使用
-include $(DEPS)将依赖文件引入 Makefile; - 验证了修改头文件后,相关
.o文件会自动重新编译; - 进一步理解了真实 C 工程中的完整增量编译机制。
Day06 的核心可以总结为一句话:
.d 文件记录每个 .o 文件依赖哪些 .c 和 .h 文件, Makefile 通过包含 .d 文件,实现头文件级别的增量编译。这一步对于后续学习嵌入式工程、驱动开发、模块化编程、复杂 Makefile 和交叉编译非常重要。
十四、项目源码
本次 Day06 学习代码已上传至 GitHub:
https://github.com/jdai10590-afk/Embedded-C-Learning-Projects/tree/main/day06