「make run」に引数を渡す


354

私はMakefileを使用しています。

私はと呼ばれるターゲット持っているrunビルドターゲットを実行します。簡略化すると、次のようになります。

prog: ....
  ...

run: prog
  ./prog

引数を渡す方法はありますか?そのため

make run asdf --> ./prog asdf
make run the dog kicked the cat --> ./prog the dog kicked the cat

ありがとう!


回答:


264

私はあなたが望むことを正確に行う方法を知りませんが、回避策は次のとおりです:

run: ./prog
    ./prog $(ARGS)

次に:

make ARGS="asdf" run
# or
make run ARGS="asdf"

27
@Rob:$()はより移植性が高く、Nmakeおよびmakeで機能します。
John Knoeller、2010

7
@Rob:Nmakeはマクロ展開のために$ {}をサポートしたことがなく、今はmakeの古い形式のようです。$()は、これまでに見てきたすべてのオンラインチュートリアルで推奨されています。$()は、bashなどの他のツールとも一貫性があります。
John Knoeller、2010

10
多分それは古風です。私は常に$ {}を使用してきましたが、GNU Makeのマニュアルでは「変数の値を置き換えるには、ドル記号の後に括弧または中括弧で変数名を記述します。$(foo)' or $ {foo} 'は、変数「foo」。」そして、$()のみが使用されている例を示します。まぁ。
Jakob Borg、

7
ジョンと落ち着いて乾杯、私は戻って、提案が私の最初の版のOReillyの本「Managing Projects with Make」からのものであることを見ました。著者は、()と両方を実行できるマクロを使用したアーカイブ置換に関するルールを述べていますが、区別するために{}を使用することを推奨しています。しかし...現在、「GNU Makeを使用したプロジェクトの管理」というタイトルが付けられた新版では、全体にわたって()を使用しています。図に行く....私は近代化する必要がありますね!( - :私はまだ{}さんのMS NMAKEがbarfsかかわらことを驚いて
ロブ・ウェルズ

1
@xealits確かに- ここ
helvete

198

この質問はほぼ3年前のものですが、とにかく...

GNU makeを使用している場合、これは簡単に実行できます。唯一の問題はmake、コマンドラインの非オプション引数をターゲットとして解釈することです。解決策はそれらを何もしないターゲットに変えることですので、make文句は言いません:

# If the first argument is "run"...
ifeq (run,$(firstword $(MAKECMDGOALS)))
  # use the rest as arguments for "run"
  RUN_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
  # ...and turn them into do-nothing targets
  $(eval $(RUN_ARGS):;@:)
endif

prog: # ...
    # ...

.PHONY: run
run : prog
    @echo prog $(RUN_ARGS)

これを実行すると:

$ make run foo bar baz
prog foo bar baz

2
:それはダッシュで始まる引数に動作していないよう除いてこれは素晴らしいですprog foo bar --baz
ingydotnet

22
その場合にも機能しますが、コマンドラインオプションとしてmake解釈--bazしないように指示する必要がありますmake -- prog foo bar --baz--手段「この後のすべてのものは、引数、オプションではありません」。
Idelic 2013年

RUN_ARGSこれを使用するためのデフォルト値をどのように定義しますか?
2013年

多分にelseブランチを追加してifeq設定RUN_ARGSしますか?
Idelic 2014

1
青い点が良い点!しかし、そのための解決策があります。「eval」行を$(eval $(RUN_ARGS):dummy;@:)に置き換えますが、ダミーターゲットは定義されていません。
Lucas Cimon、2014年


34

以下のように変数をMakefileに渡すことができます。

run:
    @echo ./prog $$FOO

使用法:

$ make run FOO="the dog kicked the cat"
./prog the dog kicked the cat

または:

$ FOO="the dog kicked the cat" make run
./prog the dog kicked the cat

または、ベータ版が提供するソリューションを使用します。

run:
    @echo ./prog $(filter-out $@,$(MAKECMDGOALS))
%:
    @:

%:-タスク名に一致するルール。 @:-空のレシピ=何もしない

使用法:

$ make run the dog kicked the cat
./prog the dog kicked the cat

22

TL; DRはこれを行わないでください

$ make run arg

代わりにスクリプトを作成します。

#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"

これを行います:

$ ./buildandrunprog.sh arg

述べられた質問への答え:

レシピで変数を使用できます

run: prog
    ./prog $(var)

次に、変数割り当てを引数として渡して、

$ make run var=arg

これが実行され./prog argます。

ただし、落とし穴に注意してください。この方法と他の方法の落とし穴については、後で詳しく説明します。


質問の背後にある想定された意図への回答:

前提:progいくつかの引数を指定して実行したいが、必要に応じて実行する前に再構築する。

答え:必要に応じて再構築するスクリプトを作成し、argsを使用してprogを実行します

#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"

このスクリプトにより、意図が非常に明確になります。makeを使用して、ビルドに適しています。シェルスクリプトを使用して、バッチ処理に適しています。

さらに、makefileのすべての警告なしに、シェルスクリプトの完全な柔軟性と表現力を使用して、他に必要なことをすべて実行できます。

また、呼び出し構文は実質的に同じになりました。

$ ./buildandrunprog.sh foo "bar baz"

次と比較:

$ ./prog foo "bar baz"

対比して

$ make run var="foo bar\ baz"

バックグラウンド:

makeは、引数をターゲットに渡すようには設計されていません。コマンドラインのすべての引数は、目標(別名ターゲット)、オプション、または変数の割り当てとして解釈されます。

これを実行すると:

$ make run foo --wat var=arg

makeは、レシピに従って更新することを解釈runfoo、目標(ターゲット)として更新します。--watmakeのオプションとして。そして、var=arg変数の割り当てなど。

詳細については、https//www.gnu.org/software/make/manual/html_node/Goals.html#Goalsを参照してください。

用語については、https//www.gnu.org/software/make/manual/html_node/Rule-Introduction.html#Rule-Introductionを参照してください。


変数の割り当て方法とそれに対して私が推奨しない理由について

$ make run var=arg

レシピの変数

run: prog
    ./prog $(var)

これは、引数をレシピに渡す最も「正確な」簡単な方法です。ただし、引数を使用してプログラムを実行するために使用できますが、そのように使用するように設計されていません。https://www.gnu.org/software/make/manual/html_node/Overriding.html#Overridingを参照してください

私の意見では、これには大きな欠点が1つprogありますarg。実行したいのは、引数を指定して実行することです。しかし、書く代わりに:

$ ./prog arg

あなたは書いている:

$ make run var=arg

これは、複数の引数またはスペースを含む引数を渡そうとするとさらに厄介になります。

$ make run var="foo bar\ baz"
./prog foo bar\ baz
argcount: 2
arg: foo
arg: bar baz

次と比較:

$ ./prog foo "bar baz"
argcount: 2
arg: foo
arg: bar baz

記録のために、これは私のprogように見えます:

#! /bin/sh
echo "argcount: $#"
for arg in "$@"; do
  echo "arg: $arg"
done

また$(var)、makefileでは引用符で囲まないでください。

run: prog
    ./prog "$(var)"

prog常に1つの引数しか取得しないためです。

$ make run var="foo bar\ baz"
./prog "foo bar\ baz"
argcount: 1
arg: foo bar\ baz

これが私がこのルートに対して推奨する理由です。


完全を期すために、「引数を渡して実行する」ための他の方法をいくつか示します。

方法1:

run: prog
    ./prog $(filter-out $@, $(MAKECMDGOALS))

%:
    @true

超短い説明:目標のリストから現在の目標を除外します。%他の目標を黙って無視するために何もしないすべてのターゲットをキャッチ()を作成します

方法2:

ifeq (run, $(firstword $(MAKECMDGOALS)))
  runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
  $(eval $(runargs):;@true)
endif

run:
    ./prog $(runargs)

非常に短い説明:ターゲットがrun最初の目標を削除し、残りの目標に対してはを使用して何もターゲットを作成しない場合eval

どちらもこのようなものを書くことができます

$ make run arg1 arg2

より詳細な説明については、makeのマニュアルを参照してくださいhttps : //www.gnu.org/software/make/manual/html_node/index.html

方法1の問題:

  • ダッシュで始まる引数はmakeによって解釈され、ゴールとして渡されません。

    $ make run --foo --bar
    

    回避策

    $ make run -- --foo --bar
    
  • 等号の引数はmakeによって解釈され、渡されません

    $ make run foo=bar
    

    回避策はありません

  • スペースを含む引数は扱いにくい

    $ make run foo "bar\ baz"
    

    回避策はありません

  • 引数がrun(ターゲットと等しい)場合、それも削除されます

    $ make run foo bar run
    

    ./prog foo bar代わりに実行されます./prog foo bar run

    方法2で可能な回避策

  • 引数が正当なターゲットである場合、それも実行されます。

    $ make run foo bar clean
    

    実行されます./prog foo bar cleanが、ターゲットのレシピもclean存在します(存在する場合)。

    方法2で可能な回避策

  • 正当なターゲットを誤って入力すると、catch allターゲットのため、黙って無視されます。

    $ make celan
    

    黙って無視しcelanます。

    回避策は、すべてを冗長にすることです。何が起こるかがわかります。しかし、それは正当な出力に対して多くのノイズを作成します。

方法2の問題:

  • 引数が既存のターゲットと同じ名前の場合、makeは上書きされるという警告を出力します。

    私が知っている回避策はありません

  • 等号のある引数は引き続きmakeによって解釈され、渡されません

    回避策はありません

  • スペースを含む引数はまだ扱いにくい

    回避策はありません

  • スペースを区切った引数evalを作成しようとすると、ターゲットは何も行われません。

    回避策:上記のように何もしないグローバルキャッチオールターゲットを作成します。上記のような問題があるため、タイプミスした正当なターゲットは再び黙って無視されます。

  • eval実行時にmakefileを変更するために使用します。読みやすさとデバッグのしやすさ、そして驚きの原則という点で、どれほど悪化するでしょうか。

    回避策:これを行わないでください!! 1代わりにmakeを実行してからを実行するシェルスクリプトを記述しますprog

私はgnu makeのみを使用してテストしました。他のmakeは異なる動作をする場合があります。


TL; DRはこれを行わないでください

$ make run arg

代わりにスクリプトを作成します。

#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"

これを行います:

$ ./buildandrunprog.sh arg

12

これらのユースケースのいくつかに役立つ可能性のある別のソリューションを次に示します。

test-%:
    $(PYTHON) run-tests.py $@

つまり、プレフィックス(test-この場合)を選択し、ターゲット名を直接プログラム/ランナーに渡します。これは、ターゲットの名前を基になるプログラムに役立つものにアンラップできるランナースクリプトが含まれている場合に、ほとんど役に立ちます。


2
を使用$*して、に一致したターゲットの一部のみを渡すこともでき%ます。
Malvineous

9

いいえ。GNUmakeのmanページの構文を見る

make [-f makefile] [options] ... [target] ...

複数のターゲットを指定できるため、「いいえ」(少なくとも、指定したとおりの方法では「いいえ」)。


4

コマンドラインで各n番目の引数を明示的に抽出できます。これを行うには、変数MAKECMDGOALSを使用できます。これは、 'make'に指定されたコマンドライン引数のリストを保持し、ターゲットのリストとして解釈します。n番目の引数を抽出する場合は、その変数を「単語」関数と組み合わせて使用​​できます。たとえば、2番目の引数が必要な場合は、次のように変数に格納できます。

second_argument := $(word 2, $(MAKECMDGOALS) )

これにより、その引数に対してmakeコマンドも実行されます。make: *** No rule to make target 'arg'. Stop.
ThomasReggi 2016年

2

anonがrun: ./prog右の部分は対象にならなければならないように、少し奇妙に見えるrun: prog良く見えます。

私は簡単に提案します:

.PHONY: run

run:
        prog $(arg1)

追加したいと思います、その引数は渡すことができます:

  1. 引数として: make arg1="asdf" run
  2. または環境として定義されます: arg1="asdf" make run

2

これが私の例です。Dev-Cppに付属のmingw32-make.exeを使用してWindows 7で書いていることに注意してください。(c:\ Windows \ System32 \ make.batがあるので、コマンドはまだ「make」と呼ばれています。)

clean:
    $(RM) $(OBJ) $(BIN) 
    @echo off
    if "${backup}" NEQ "" ( mkdir ${backup} 2> nul && copy * ${backup} )

定期的な掃除の使い方:

make clean

mydir /内のバックアップをクリーニングおよび作成するための使用法:

make clean backup=mydir

2

これをあまり誇りに思っていませんが、環境変数を渡したくなかったため、次のように、既定のコマンドを実行する方法を逆にしました。

run:
    @echo command-you-want

これは実行したいコマンドを出力するので、サブシェルでそれを評価するだけです:

$(make run) args to my command

4
2年後のこの回答を振り返ってみてください-なぜ私は環境変数を使いたくないほど頑固で、なぜ別のコマンドの生成をインライン化する方が良いと思いましたか?
Conrad.Dean

0

等号(=)で引数を取得する方法を見つけました!回答は特に@lesmanaの回答への追加です(これが最も完全であり、ここで説明されているため)、コメントとして書くには大きすぎます。繰り返しますが、私は彼のメッセージを繰り返します。TL; DRはこれを実行しようとしないでください!

私は私の引数を処理する方法が必要でした--xyz-enabled=false(デフォルトがtrueであるため)、これはこれがmakeターゲットではなく、したがっての一部ではないことを今では誰もが知ってい$(MAKECMDGOALS)ます。

エコーしてmakeのすべての変数を調べている間、$(.VARIABLES)私はこれらの興味深い出力を得ました:

[...] -*-command-variables-*- --xyz-enabled [...]

これにより、2つの方法が可能になります。すべてをaで開始する--(ケースに当てはまる場合)か、GNU make固有(おそらく使用することを目的としていない)変数を調べます-*-command-variables-*-。**追加オプションについてはフッターを参照してください**私の場合、この変数は保持されています:

--xyz-enabled=false

この変数を使用して$(MAKECMDGOALS)、次のように定義することで、既存のソリューションと組み合わせることができます。

# the other technique to invalidate other targets is still required, see linked post
run:
    @echo ./prog $(-*-command-variables-*-) $(filter-out $@,$(MAKECMDGOALS))`

そしてそれを(引数の順序を明示的に混ぜ合わせて)使用します:

make run -- config --xyz-enabled=false over=9000 --foo=bar show  isit=alwaysreversed? --help

戻ってきた:

./prog isit=alwaysreversed? --foo=bar over=9000 --xyz-enabled=false config show --help

ご覧のとおり、引数の順序はすべて失われています。「割り当て」引数を持つ部分は逆になっているようです。「ターゲット」引数の順序は保持されます。最初に「割り当て」引数を配置しました。うまくいけば、プログラムは引数がどこに配置されてもかまいません。


更新:以下の変数も有望に見えるようにします:

MAKEFLAGS =  -- isit=alwaysreverse? --foo=bar over=9000 --xyz-enabled=false
MAKEOVERRIDES = isit=alwaysreverse? --foo=bar over=9000 --xyz-enabled=false

-2

私が使用するもう1つのトリックは、空走を行うように-n指示makeするフラグです。例えば、

$ make install -n 
# Outputs the string: helm install stable/airflow --name airflow -f values.yaml
$ eval $(make install -n) --dry-run --debug
# Runs: helm install stable/airflow --name airflow -f values.yaml --dry-run --debug
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.