个人网站做项目,通州网络推广,图片站手机网站怎么做,龙岩招聘网最新招聘在龙岩的工作一、简介在前面的文章中#xff0c;我们介绍了makefile如何通过CFLAGS选项#xff0c;设置包含.h的路径。但是有个问题#xff0c;如果每次修改了.h的内容#xff0c;make时并不会重新加载.h的内容。本章就来解决这个问题。二、实操文件路径如下#xff1a;project/
├──…一、简介 在前面的文章中我们介绍了makefile如何通过CFLAGS选项设置包含.h的路径。但是有个问题如果每次修改了.h的内容make时并不会重新加载.h的内容。本章就来解决这个问题。二、实操 文件路径如下
project/
├── a.c
└── include/└── a.h a.c文件内容如下
#include stdio.h
#include a.hint main(void)
{printf(this is a\r\n);printf(DEMO %d\r\n,DEMO);
} a.h中定义宏DEMO。
#define DEMO 0 Makefile如下
CC : gcc # 指定编译器
SRC : a.c # 指定源文件
CFLAGS : -I./include -O2 -Wall -Werror
TARGET : test
OBJ : $(SRC:.c.o)all: $(TARGET) echo 所有目标构建完成$(TARGET): $(OBJ)$(CC) -o $ $^%.o: %.c$(CC) $(CFLAGS) -o $ -c $ clean: rm -f $(OBJ) $(TARGET).PHONY: all clean 因为CFLAGS中使用了-I./include来制定在include文件夹中搜索.h文件所以程序是可以正常找到a.h并获取到其内容的。 执行一下。 程序运行正常此时修改a.h的内容。
#define DEMO 1 重新make。 可以看到程序并没有重新加载DEMO的值。从make的打印内容也可以看到程序只执行了如下代码
all: $(TARGET) echo 所有目标构建完成 如果希望每次重新加载.h内容就需要修改makefile如下
CC : gcc # 指定编译器
SRC : a.c # 指定源文件
CFLAGS : -I./include -O2 -Wall -Werror
TARGET : test
OBJ : $(SRC:.c.o)
DEP : $(OBJ:.o.d)all: $(TARGET) echo 所有目标构建完成-include $(DEP)$(TARGET): $(OBJ)$(CC) -o $ $^%.o: %.c$(CC) $(CFLAGS) -o $ -c $ -MMDclean: rm -f $(OBJ) $(TARGET) $(DEP).PHONY: all clean 执行一下 可以看到make后修改.h中demo的值再次make重新加载了.h的内容。三、解析 DEP : $(OBJ:.o.d) 如果希望每次.h的修改被makefile知道那么就需要了解依赖文件.d。依赖文件告诉makefile在编译的时候.o文件依赖于哪些.c和.h。而$(OBJ:.o.d)就是把.o文件转为换.d文件。让makefile知道.o文件依赖于哪些.d文件。 看一下a.d文件内容 可以看到生成的a.h文件说明了a.o依赖于a.c和a.h那么每次make时就会去查看a.h是否发生改变。 -MMD 仅仅有a.d文件还是不够的需要让makefile知道这些依赖文件是需要被查看。 -MMD参数用于自动生成源文件依赖关系作用如下分析源文件如 .c/.cpp中包含的头文件.h生成依赖文件通常以 .d 为扩展名记录哪些头文件被源文件引用 与-md的区别 -md包含所有头文件的依赖包含系统头文件。 -mmd仅包含 用户自定义头文件 的依赖不包含系统头文件如 stdio.h、iostream 等只生成用户自定义头文件的依赖关系 -include $(DEP)includeMakefile 的关键字用于引入其他文件的内容类似 C 语言的 #include被引入的文件会被视为当前 Makefile 的一部分。- 前缀表示 “忽略错误”。如果 $(DEP) 指向的文件不存在或有错误Make 不会报错而是继续执行这在首次编译时很有用因为此时依赖文件可能还未生成 为什么要写在all之后 如果写在all之前makefile可能会出现解析边缘问题。例如我们把include写在all之前如下 修改.h后重新make。 发现DEMO的值并没有改变。并且程序只执行了$(CC) $(CFLAGS) -o $ -c $ -MMD这句而没有执行$(CC) -o $ $^。 重新执行Make all 成功了。说明make时并没有把make all作为默认目标文件。 Make 解析 Makefile 的流程是 “从上到下逐行扫描遇到目标规则就记录遇到 -include 就立即加载并解析”。当 -include $(DEP) 放在 all 之前时会触发以下隐藏逻辑Make 先扫描变量定义CC、SRC、OBJ 等遇到 -include a.d立即加载并解析 a.d 中的 a.o: a.c include/a.h这是一个 “依赖规则”但 Make 会将其视为 a.o 目标的补充定义此时Make 的 “目标列表” 中已存在 a.o 目标来自 .d 文件继续扫描到 all: $(TARGET) 时Make 会记录 all 目标但在某些版本的 Make 中如GNU Make 4.2.1若之前已存在 “非隐藏目标”a.o会错误地将 a.o 提升为 “默认目标候选”最终Make 执行时只处理了 “默认目标候选” a.o 的更新完全跳过了 all 和 test 目标 这就是为什么只编译 a.o、不链接 test 的根本原因。