在构建具有递归依赖关系的库时,我有这个片段:
$(LIBRARY) : $(OBJECTS) | $(LIBDIR) # objects is all the obj/*.o
$(AR) ...
obj/%.o : %.cpp obj/%.d
$(CC) ...
build : $(DEPENDENCIES) $(LIBRARY)
$(DEPENDENCIES):
$(MAKE) -C $(ROOT)/$@
如果我运行make
,这是有效的。一切按照正确的顺序按预期构建。但是如果我运行make -jN
,那么库会以错误的顺序构建,因为我实际上并没有设置任何依赖性排序规则,这导致了许多未定义的引用。
如果我添加规则:
$(OBJECTS) : $(DEPENDENCIES)
然后运行make每次重建每个库,无论更改(DEPENDENCIES
是假的,但我不明白为什么它实际上重建了一切)。如何在不必每次重建所有内容的情况下为并行构建强制执行正确的排序?
答案 0 :(得分:7)
我将为您提供如何设置makefile以保证的一般指导原则:
一个。重建那个,只有那个必要的,
湾正确地处理并行性。
有些人已经要求了一些好的原则",所以他们在这里。
使用这些原则重写您的makefile,并确保您正常工作。
十诫:
您应该调用make
制作target
(或目标)或默认目标,这是您的Makefile中的第一个目标。您的Makefile中的目标位于:
有两种目标:真实和"假的"。真正的目标是您想要(重新)创建的实际文件(或目录)。伪目标是抽象概念,而不是真实文件,但它通常表示一组真实文件。
Makefile中列出的目标也可能有%
,在这种情况下,它是一个模式目标,可以匹配多个目标,真实或虚假。
来源是未列为目标的文件,并且在调用make
之前已存在。
目标"取决于" on"先决条件"在目标
:
之后
真正的目标必须有一个" recipe",这是目标行下的shell脚本。配方应该只写一个文件和一个文件,即目标文件。目标文件应在配方中称为$@
。
如果配方写入多个文件,请将其分解为单个目标的多个配方。
配方可能会读取许多文件:这些文件必须列为先决条件。
虚假目标不得有食谱。
假目标可以依赖于其他虚假目标,真实目标或来源。真正的目标必须仅依赖于真实的目标或来源。最终(递归)一切都只取决于来源。
你不能在食谱中递归地调用make
,除了一种情况和一种情况:你有一些完全自己构建的子目录,而不会读取你自己以外的任何来源或目标。
在这种特殊情况下,你应该有一个虚假的目标子目录和食谱:
.PHONY: subdirectory
subdirectory:
$(MAKE) -C $@
include
。 注意:我并不是说你不能在违反这些原则的情况下编写正确的Makefile。你可以而且有时是必要的。但要做到这一点,你必须知道自己在做什么,并了解更高级的概念。你不应该开始学习那种方式,但首先要按照上述原则开始编写Makefile。