回答:
私はあなたが望むことを正確に行う方法を知りませんが、回避策は次のとおりです:
run: ./prog
./prog $(ARGS)
次に:
make ARGS="asdf" run
# or
make run ARGS="asdf"
$(foo)' or
$ {foo} 'は、変数「foo」。」そして、$()のみが使用されている例を示します。まぁ。
この質問はほぼ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
prog foo bar --baz
make
解釈--baz
しないように指示する必要がありますmake -- prog foo bar --baz
。--
手段「この後のすべてのものは、引数、オプションではありません」。
RUN_ARGS
これを使用するためのデフォルト値をどのように定義しますか?
else
ブランチを追加してifeq
設定RUN_ARGS
しますか?
$(eval $(RUN_ARGS):dummy;@:)
に置き換えますが、ダミーターゲットは定義されていません。
以下のように変数を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
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は、レシピに従って更新することを解釈run
しfoo
、目標(ターゲット)として更新します。--wat
makeのオプションとして。そして、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
これらのユースケースのいくつかに役立つ可能性のある別のソリューションを次に示します。
test-%:
$(PYTHON) run-tests.py $@
つまり、プレフィックス(test-
この場合)を選択し、ターゲット名を直接プログラム/ランナーに渡します。これは、ターゲットの名前を基になるプログラムに役立つものにアンラップできるランナースクリプトが含まれている場合に、ほとんど役に立ちます。
$*
して、に一致したターゲットの一部のみを渡すこともでき%
ます。
コマンドラインで各n番目の引数を明示的に抽出できます。これを行うには、変数MAKECMDGOALSを使用できます。これは、 'make'に指定されたコマンドライン引数のリストを保持し、ターゲットのリストとして解釈します。n番目の引数を抽出する場合は、その変数を「単語」関数と組み合わせて使用できます。たとえば、2番目の引数が必要な場合は、次のように変数に格納できます。
second_argument := $(word 2, $(MAKECMDGOALS) )
make: *** No rule to make target 'arg'. Stop.
これが私の例です。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
これをあまり誇りに思っていませんが、環境変数を渡したくなかったため、次のように、既定のコマンドを実行する方法を逆にしました。
run:
@echo command-you-want
これは実行したいコマンドを出力するので、サブシェルでそれを評価するだけです:
$(make run) args to my command
等号(=)で引数を取得する方法を見つけました!回答は特に@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