3

次のことを行うメイクファイル (GNU make) を作成しようとしています。

  1. スクリプトは一連のファイルを生成します。ファイル名は前もって知られていません。
  2. これらのファイルはそれぞれ別のファイルに変換されます。
  3. すべてが変換された後、これらのファイルはすべて 1 つの出力ファイルに結合されます。

中間のソース ファイルとターゲット ファイルが事前にわからない「ベルカーブ」パターンの依存関係グラフを含むメイクファイルを作成するにはどうすればよいですか?

概念的には、次のことを行っています。

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 を作成するターゲットを実行する前に、ターゲットとソースを評価します。また、結合する前にすべての svg が変換されていることを確認する方法はありません。

依存関係を作成してメイクファイルに含めることができることに気付きましたが、これも機能させるのに苦労しました。

.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」が作成される可能性があることを make に通知する方法はありません。

4

3 に答える 3

3

ディレクティブを移動すると違いが生じることに驚きましたがinclude(どのバージョンの Make を使用していますか?)、もっと簡単な方法があります。あなたの の使用はdeps.d事実上 Make の再帰的な使用です -- Make は自分自身を 2 回目に実行するように手配しています -- したがって、それを公式にすることもできます:

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 $^ $@
于 2012-07-06T13:47:34.787 に答える
1

なぜこれが機能するのかわからないため、これは正確な答えではありませんが、インクルードされたファイルを作成するターゲットのincludeにディレクティブを移動すると、すべてが機能することがわかりました。

つまり、これを行います:

deps.d:
    ....

include deps.d

私の deps.d には十分な依存関係情報が含まれているため、中間ターゲットallpdfsファイルを用意する必要はありません。すべてがうまく機能しmake -jます。

ただし、なぜこれが機能するのかわかりません。インクルードドキュメントは私を啓発していません。

アップデート

make マニュアルの一番下に、 Automatic Prerequisites について説明している次のメモがあることに気付きました。

「.d」ファイルにはターゲット定義が含まれていることに注意してください。makefile の最初のデフォルト ゴールの後に必ず include ディレクティブを配置する必要があります。そうしないと、ランダムなオブジェクト ファイルがデフォルト ゴールになる危険があります。Make の仕組み を参照してください。

何が起こったのかというと、生成された deps.d 内の最初のルールがデフォルトのターゲットになり、不可解な時期尚早にビルドが完了してしまうということです。したがって、解決策は、includeディレクティブが意図したデフォルト ターゲットの前にないことを確認することです。

于 2012-07-06T10:01:29.323 に答える