我试图创建一个执行以下操作的makefile(GNU make):
如何使用" bellcurve" -patterned依赖关系图创建一个makefile,其中中间源文件和目标文件事先不知道?
从概念上讲,我正在做以下事情:
combined.pdf: $(filter combined.pdf, $(wildcard *.pdf))
cat *.pdf > combined.pdf
%.pdf: %.svg
cp $^ $@
$(wildcard *.svg):
# recipe is for simple example
# actually the *.svg files are not known in advance
echo a > a.svg
echo b > b.svg
echo c > c.svg
.PHONY: clean
clean:
${RM} *.svg *.pdf *.d
当然这不起作用:Make在运行实际创建svg的目标之前评估目标和源。而且,在组合它们之前,没有办法确保所有的svgs都被转换。
我意识到我可以创建依赖项并将它们包含在makefile中,但我也无法使其工作:
.PHONY: clean
include deps.d
combined.pdf: deps.d
cat *.pdf > combined.pdf
%.pdf: %.svg
cp $^ $@
deps.d:
@# recipe is for simple example
@# actually the *.svg files are not known in advance
echo a > a.svg
echo b > b.svg
echo c > c.svg
@# we know what files exist now, so we can establish dependencies
@# "a.pdf : a.svg"
echo *.svg : > deps.d
@# combined.pdf: a.pdf b.pdf c.pdf
ls *.svg \
| awk '{targetfn=$$0; sub(/\.svg$$/, ".pdf", targetfn); print targetfn, ":", $$0;}' \
>> deps.d
@# combined.pdf: a.pdf b.pdf c.pdf
echo combined.pdf : $$(echo *.svg | sed -e 's/\.svg/\.pdf/g') >> deps.d
clean:
${RM} *.pdf *.svg *.d
然而,这仍然没有正确连接依赖图。当我运行它时,退出如下:
Makefile:3: deps.d: No such file or directory
echo a > a.svg
echo b > b.svg
echo c > c.svg
echo *.svg : > deps.d
ls *.svg \
| awk '{targetfn=$0; sub(/\.svg$/, ".pdf", targetfn); print targetfn, ":", $0;}' \
>> deps.d
echo combined.pdf : $(echo *.svg | sed -e 's/\.svg/\.pdf/g') >> deps.d
make: Nothing to be done for `a.svg'.
我似乎还有一个问题,即make并不知道deps.d中的规则。
此外,这仍然无法解决构建所有依赖项的问题。我想过使用这样的标记文件:
%.pdf: %.svg
cp $^ $@
@# if all svgs are converted, touch a target allpdfs
if [ $(ls -1 *.svg | wc -l) -eq $(ls -1 *.pdf | grep -v combined\.pdf | wc -l) ]; touch allpdfs; fi
但是没有办法告知那个" allpdfs"可以通过此规则创建。
答案 0 :(得分:3)
我很惊讶移动include
指令有所不同(你使用的是什么版本的Make?),但有一种更简单的方法。你对deps.d
的使用实际上是Make-Make的递归使用,它正在安排第二次执行 - 所以我们不妨将其正式化:
combined.pdf: ALL_SVGS
$(MAKE) ALL_PDFS
rm -f $@ # just in case it exists already
cat *.pdf > $@
.PHONY: ALL_SVGS
ALL_SVGS:
# recipe is for simple example
# actually the *.svg files are not known in advance
echo a > a.svg
echo b > b.svg
echo c > c.svg
# These variables will be empty in the first execution of Make
SVGS = $(wildcard *.svg)
PDFS = $(patsubst %.svg,%.pdf,$(SVGS))
.PHONY: ALL_PDFS
ALL_PDFS: $(PDFS))
%.pdf: %.svg
cp $^ $@
答案 1 :(得分:1)
这不是答案,因为我不知道为什么会这样,但我发现如果我在之后移动include
指令创建包含文件的目标,一切正常。
即。这样做:
deps.d:
....
include deps.d
因为我的deps.d包含足够的依赖信息,所以不需要有中间目标allpdfs
文件。一切正常,即使是make -j
。
但是,我不知道为什么这是有效的。 include documentation并没有启发我。
我注意到以下注释at the very bottom of the make manual discussing Automatic Prerequisites:
请注意,'。d'文件包含目标定义;您应该确保将include指令放在makefile中的第一个默认目标之后,或者冒着让随机对象文件成为默认目标的风险。请参阅How Make Works。
所以发生的事情是生成的deps.d 中的第一个规则成为默认目标,导致构建的神秘过早完成。因此,解决方案只是确保include
指令不在预期的默认目标之前。
答案 2 :(得分:1)
我只是在稍微不同的设置中处理这个确切的问题。这是一个干净的解决方案 - 不需要递归等(如果你愿意,你可以调整sed):
include deps.d
combined.pdf:
cat *.pdf > combined.pdf
%.pdf: %.svg
cp $^ $@
deps.d:
echo a > a.svg
echo b > b.svg
echo c > c.svg
echo 'combined.pdf:' *.svg | sed 's/\.svg/\.pdf/g' > deps.d
享受!