论坛里有人写了一个用于自动生成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 很复杂的时候性能不如前文的方法。