Make 不是一种过程语言,因此将其视为一种违背常规的语言。你的 makefile 将很难扩展,并且可能会导致微妙的错误。
有一个更好的方法 http://mad-scientist.net/make/autodep.html由 Tom Tromey 提出,它干净、高效且可扩展。诀窍是要认识到您可以在与目标文件相同的步骤中构建依赖项文件。依赖关系只是告诉 Make 对象何时需要重建;第一次构建对象时不需要它们,因为 Make 知道必须构建该对象。如果依赖关系发生变化,那只能是因为源代码或旧依赖关系中的某些内容发生了变化,因此 Make 再次知道必须重建该对象。 (这并不明显,所以可能需要一点思考。)
$(CORE_OBJS): build/%.o: src/%.c
$(CC) -c $(CFLAGS) $< -o $@
$(CC) -MM -MF build/$*.d $<
-include build/*.d
还有一个问题:如果您更改代码以删除依赖项 - 并删除该文件 - 您将无法重建,因为旧的依赖项列表仍然需要一个无法再找到的文件。复杂的解决方案是处理依赖文件,以使每个先决条件(例如标头)本身成为目标,无需命令,以便可以假设在需要时重建它:
$(CORE_OBJS): build/%.o: src/%.c
$(CC) -c $(CFLAGS) $< -o $@
$(CC) -MM -MF build/$*.d $<
@cp build/$*.d build/$*.P
@sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < build/$*.P >> build/$*.d;
@rm build/$*.P
一种更粗略但几乎同样万无一失的方法是为标头和源添加包罗万象的规则:
$(CORE_OBJS): build/%.o: src/%.c
$(CC) -c $(CFLAGS) $< -o $@
$(CC) -MM -MF build/$*.d $<
%.cc %.h:
EDIT:
分解新命令:
The -MM
选项告诉 gcc 生成一个make
目标文件的规则,而不是预处理或编译。默认情况下是将规则发送到它将发送预处理输出的任何位置,通常是标准输出。
The -MF
选项,与-MM
,指定输出文件。所以-MM -MF build/$*.d
会将规则放在我们想要的地方。
因此以下两个命令(几乎总是)是等效的:
$(CC) -MM -MF build/$*.d $<
$(CC) -MM $< > build/$*.d
(我省略了-I$(...)
以及使用的可能性-MMD
选项,因为两者都有点复杂并且不是问题的重点。)