在Makefile中自动生成依赖
论坛里有人写了一个用于自动生成C/C++依赖的脚本。但是他的脚本处理不同目录的源文件时会有些问题,.o 会生成在当前目录,而不是和 .cc 同一个目录。
gcc 其实有一些生成用于 Makefile 规则的选项,-M 等,说明如下:
-
-MM,忽略依赖中的系统头文件 -
-MF,指定生成的规则文件的路径 -
-MT,指定规则的目标 -
-MP,对每一个依赖创建一个force target,典型输出:test.o: test.c test.h test.h:没有这个选项的话是不会有
test.h:的
我写的 Makefile 如下,注意要把规则中的8格替换成tab。
PROG := main
SRCS := $(PROG).c
$(PROG): $(SRCS:.c=.o)
$(LINK.c) $^ -o $@
sinclude $(SRCS:.c=.d)
%.o: %.c
gcc -MM -MP -MT $@ -MF $(@:.o=.d) $<
$(COMPILE.c) $< -o $@
比较难说明每个规则的作用,所以还是用实例好了。
- 一开始,
*.o*.d都不存在,只有一个main.c - 执行
make,make没法读取sinclude那行表示的文件main.d,但由于是sinclude,忽略这个错误 - 尝试重建
main,发现需要的main.o不存在 - 因此尝试先重建
main.c。执行规则%.o: %.c,生成main.o的同时也 生成了main.d。假设main.c包含一个头文件a.h,那么main.d的内容将会是: main.o: main.c foo/a.h foo/a.h:
之后如果修改 main.c 或者 foo/a.h,因为 main.d 中的规则都会重建 main.o。
再看添加新依赖 bar/b.h 的情况,没错,这时我们的 main.d 是过期的,不能反映 main.c 的真实依赖情况。但注意到 main.d 的过期必然蕴含:main.c 被修改了。根据规则 %.o: %.c,再次重建 main.d 和 main.o。
假设我们删除 main.c 中的 #include "foo/a.h",同样的,main.d 过期了,不能反映 main.c 的真实依赖情况。但注意到 main.d 的过期必然蕴含:main.c 被修改了。根据规则 %.o: %.c,再次重建 main.d 和 main.o。
如果我们不改动 main.c 而是直接删除 foo/a.h,那么根据 main.o: main.c foo/a.h,无法重建 main.o,make 报错。注意:foor/a.h 是 force target,它不存在的话不会报错,只是让依赖它的目标强制重建。这也是我们之所以使用 -MP 的原因,否则如果不存在目标为 foo/a.h 的规则,make 会报错:无法重建 foo/a.h。
还有种生成依赖的方式是让 main.o 依赖 main.d,main.d 依赖 main.c,但是这种方法可能会导致 make 的重启,当 make 很复杂的时候性能不如前文的方法。