web-dev-qa-db-ja.com

ルール実行時にmake変数を定義する

私のGNUmakefileには、一時ディレクトリを使用するルールが必要です。例えば:

out.tar: TMP := $(Shell mktemp -d)
        echo hi $(TMP)/hi.txt
        tar -C $(TMP) cf $@ .
        rm -rf $(TMP)

書かれているように、上記のルールは、ルールが解析済みのときに一時ディレクトリを作成します。これは、out.tarを常に作成しなくても、多くの一時ディレクトリが作成されることを意味します。/tmpに未使用の一時ディレクトリが散らばらないようにしたいと思います。

ルールが定義されているときではなく、ルールが起動されたときにのみ変数を定義する方法はありますか?

私の主な考えは、mktempとtarをシェルスクリプトにダンプすることですが、それはやや見苦しいようです。

180
Emil Sit

この例では、out.tarrulesが評価されるたびに、TMP変数が設定されます(および一時ディレクトリが作成されます)。 out.tarが実際に起動されたときにのみディレクトリを作成するには、ディレクトリの作成をステップに移動する必要があります。

out.tar : 
    $(eval TMP := $(Shell mktemp -d))
    @echo hi $(TMP)/hi.txt
    tar -C $(TMP) cf $@ .
    rm -rf $(TMP)

eval 関数は、makefileに手動で入力されたかのように文字列を評価します。この場合、TMP変数をShell関数呼び出しの結果に設定します。

edit(コメントへの応答):

一意の変数を作成するには、次を実行できます。

out.tar : 
    $(eval $@_TMP := $(Shell mktemp -d))
    @echo hi $($@_TMP)/hi.txt
    tar -C $($@_TMP) cf $@ .
    rm -rf $($@_TMP)

これにより、ターゲット名(この場合はout.tar)が変数に追加され、out.tar_TMPという名前の変数が生成されます。うまくいけば、競合を防ぐのに十分です。

280
e.James

これを行う比較的簡単な方法は、シーケンス全体をシェルスクリプトとして記述することです。

out.tar:
   set -e ;\
   TMP=$$(mktemp -d) ;\
   echo hi $$TMP/hi.txt ;\
   tar -C $$TMP cf $@ . ;\
   rm -rf $$TMP ;\

関連するヒントをここにまとめました: https://stackoverflow.com/a/29085684/86967

56
nobar

別の可能性は、ルールが実行されるときにMake変数を設定するために別々の行を使用することです。

たとえば、次の2つのルールを持つメイクファイルです。ルールが実行されると、一時ディレクトリが作成され、TMPが一時ディレクトリ名に設定されます。

PHONY = ruleA ruleB display

all: ruleA

ruleA: TMP = $(Shell mktemp -d testruleA_XXXX)
ruleA: display

ruleB: TMP = $(Shell mktemp -d testruleB_XXXX)
ruleB: display

display:
    echo ${TMP}

コードを実行すると、予想される結果が生成されます。

$ ls
Makefile
$ make ruleB
echo testruleB_Y4Ow
testruleB_Y4Ow
$ ls
Makefile  testruleB_Y4Ow
27
user3124434