具有依赖图的Makefile事先不知道

时间:2012-07-06 09:30:14

标签: makefile gnu-make

我试图创建一个执行以下操作的makefile(GNU make):

  1. 脚本生成一堆文件 - 事先不知道的文件名。
  2. 这些文件中的每一个都转换为不同的文件。
  3. 转换完毕后,所有这些文件将合并为一个输出文件。
  4. 如何使用" 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"可以通过此规则创建。

3 个答案:

答案 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

享受!