Makefile多目标与分离目标为模式提供了不同的结果
我的makefile失败了。我的想法是从某个文件中提取文件并将它们放在临时目录中。然后将其重新同步到源目录。由于rsync仅在文件发生更改时更新,因此除非必要,否则不会重新生成源目录中的makefile。我已将问题隔离如下:Makefile多目标与分离目标为模式提供了不同的结果,makefile,Makefile,我的makefile失败了。我的想法是从某个文件中提取文件并将它们放在临时目录中。然后将其重新同步到源目录。由于rsync仅在文件发生更改时更新,因此除非必要,否则不会重新生成源目录中的makefile。我已将问题隔离如下: .PHONY: extract clean FILES = filea1.cc filea2.cc filea3.cc \ filea1.hh filea2.hh filea3.hh
.PHONY: extract clean
FILES = filea1.cc filea2.cc filea3.cc \
filea1.hh filea2.hh filea3.hh \
filea1.py filea2.py filea3.py \
dir-cc/filea1.cc dir-cc/filea2.cc dir-cc/filea3.cc \
dir-cc/filea1.hh dir-cc/filea2.hh dir-cc/filea3.hh \
dir-py/filea1.py dir-py/filea2.py dir-py/filea3.py
PATTERN := $(sort $(addprefix build/%., $(patsubst .%,%,$(suffix $(FILES)))))
extract: $(addprefix build/, $(FILES))
$(PATTERN):
mkdir -p $(dir $@); echo "hello!" > $@
#build/%.cc:;mkdir -p $(dir $@); echo "hello!" > $@
#build/%.hh:;mkdir -p $(dir $@); echo "hello!" > $@
#build/%.py:;mkdir -p $(dir $@); echo "hello!" > $@
temp:
echo $(PATTERN)
clean:
rm -rf build
执行make temp会得到“build/%.cc build/%.hh build/%.py”,但“make extract”无法生成所有文件:
build:
dir-cc dir-py filea1.cc filea2.cc filea3.cc
build/dir-cc:
filea1.cc filea2.cc filea3.cc
build/dir-py:
filea1.py filea2.py filea3.py
build:
dir-cc filea1.cc filea1.py filea2.hh filea3.cc filea3.py
dir-py filea1.hh filea2.cc filea2.py filea3.hh
build/dir-cc:
filea1.cc filea1.hh filea2.cc filea2.hh filea3.cc filea3.hh
build/dir-py:
filea1.py filea2.py filea3.py
hh文件丢失。令人难以置信的是,在实际工作中,cc文件丢失了。无论如何,注释掉$(模式)并删除注释,以使上述代码中的目标是分开的,确实会得到所有文件:
build:
dir-cc dir-py filea1.cc filea2.cc filea3.cc
build/dir-cc:
filea1.cc filea2.cc filea3.cc
build/dir-py:
filea1.py filea2.py filea3.py
build:
dir-cc filea1.cc filea1.py filea2.hh filea3.cc filea3.py
dir-py filea1.hh filea2.cc filea2.py filea3.hh
build/dir-cc:
filea1.cc filea1.hh filea2.cc filea2.hh filea3.cc filea3.hh
build/dir-py:
filea1.py filea2.py filea3.py
由于在实际工作中,所有内容都必须是自动的,并且所有目标的规则都是相同的(因此我不必重新键入),因此我非常喜欢第一个版本。我读了手册,但我不明白为什么要这样做。我使用的是GNU Make 4.1。本节最后一段对此进行了解释: 模式规则可能有多个目标。与普通规则不同的是,这并不像许多具有相同先决条件和配方的不同规则那样起作用。如果模式规则有多个目标,make知道规则的配方负责生成所有目标。配方只执行一次以生成所有目标 您不能编写具有许多不同模式目标的模式规则,这样make将针对每个目标运行一次配方。这不是它的工作原理 对于非常简单的案例,您可以这样做:
FILETYPES := $(sort $(suffix $(FILES)))
$(foreach T,$(FILETYPES),$(eval build/%$T: ; mkdir -p $$(@D); echo "hello!" > $$@))
有一个很好的解决方案:使用普通(非模式)多目标 规则<代码>$(文件):;规则并定义要调整的模式特定变量值
将规则设置为文件扩展名。Duh。谢谢帮助很大。尽管如此,令人困惑。自从make讲述mkdir-p build/以来,这个配方似乎已经运行了不止一次;echo“hello!”>build/filea1.cc mkdir-p build/;echo“hello!”>build/filea2.cc mkdir-p build/;echo“hello!”>build/filea3.cc mkdir-p build/dir cc/;echo“hello!”>build/dir cc/filea1.cc…当然,它会为每个匹配模式运行一次。也就是说,它将为
build/filea1.cc
运行一次,但是make希望运行此配方一次也会在目标列表中创建其他模式:build/filea1.hh
和build/filea1.py
,因此它不会尝试单独构建这些模式。但是make并不认为运行一个模式会创建所有可能与这些模式匹配的文件。好吧,它可以这样说,对于遇到这种情况的任何人来说:模式规则可能有多个目标。与普通规则不同的是,这并不像许多具有相同先决条件和配方的不同规则那样起作用。如果模式规则有多个目标,那么在配方的每次运行中,make都假设构建了配方运行中多目标列表中匹配的所有目标。应该注意的是,配方确实构建了所有这样的目标,因为make只尝试构建任何目标一次。