web-dev-qa-db-ja.com

"make run"に引数を渡す

私はMakefileを使います。

ビルドターゲットを実行するrunというターゲットがあります。簡単に言うと、次のようになります。

prog: ....
  ...

run: prog
  ./prog

座ってください。これは独創的ですが、スタンディングオベーションは必要ありません。

さて、私の質問は - 引数を渡す方法はありますか?そのため

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

ありがとうございます。

304
anon

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

run: ./prog
    ./prog ${ARGS}

その後:

make ARGS="asdf" run
213
Jakob Borg

この質問はほぼ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
172
Idelic

標準のmakeでは、このようにマクロを定義することで引数を渡すことができます。

make run arg1=asdf

それからこのように使う

run: ./prog $(arg1)
   etc

make Microsoftの NMake の参照

42
John Knoeller

以下のように変数を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

あるいは、 Beta が提供する解決策を使用してください。

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

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

使用法:

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

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を使ってそれが良いことをします。シェルスクリプトを使用して、適切なことを実行します。バッチ処理。

呼び出し構文も実質的に同一です。

$ ./buildandrunprog.sh foo "bar baz"

と比較します。

$ ./prog foo "bar baz"

加えて、シェルスクリプトの完全な柔軟性と表現力を活かして、メイクファイルに関する注意をすべて払わなくても、他に必要なことをすべて実行できます。


バックグラウンド:

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

あなたがこれを実行するならば:

$ make run foo bar --wat var=arg

makeはrunfoo、およびbarをレシピに従って更新する目標(ターゲット)として解釈します。 makeのオプションとしての--wat。変数代入として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

makefileの中で$(var)を引用符で囲むと、次のようになります。

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

progは常にただ一つの引数を取ります:

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

こういうわけで私はこのルートに対してお勧めします。


完全を期すために、 "make runに引数を渡す"他の方法をいくつか示します。

方法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のマニュアルを研究してください: https://www.gnu.org/software/make/manual/html_node/index.html

方法1の問題

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

    $ make run --foo --bar
    

    workaround

    $ make run -- --foo --bar
    
  • 引数が偶然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で可能な回避策

  • スペースで引数を渡すのは面倒です

    $ make run foo "bar\ baz"
    

    回避策なし

  • 正当なターゲットを誤入力した場合、それはcatch allターゲットのために静かに無視されます。

    $ make celan
    

    celanを黙って無視するだけです。

    回避策はすべてを冗長にすることです。それで、あなたは何が起こるかわかります。しかし、それは合法的な出力に対して多くのノイズを生み出します。

方法2の問題点

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

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

  • スペースで引数を渡すことはまだ厄介です。

    回避策なし

  • スペースを含む引数は、作成しようとするevalを中断し、ターゲットは何もしません。

    回避策:グローバルキャッチオールターゲットを作成し、上記のように何もしない。上記のような問題で、タイプミスされた合法的なターゲットを再び静かに無視するでしょう。

  • 実行時にevalを使用してメイクファイルを変更します。読みやすさとデバッグのしやすさ、そして 最小の驚きの原則 の観点から、どれだけさらに悪いことができるのでしょう。

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

gNU makeを使ってテストしただけです。他の機種では動作が異なる場合があります。


TL; DRはこれを試みません

$ make run arg

代わりにスクリプトを作成してください。

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

そしてこれを行う:

$ ./buildandrunprog.sh arg
14
lesmana

これらのユースケースのいくつかを助けることができるもう一つの解決策はここにあります:

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

言い換えれば、何らかの接頭辞(この場合はtest-)を選択してから、ターゲット名を直接プログラム/ランナーに渡します。ターゲット名を基礎となるプログラムに役立つものにアンラップできる何らかのランナースクリプトが含まれている場合、これはほとんど役に立ちます。

11
djc

いいえ。GNU makeのマニュアルページの構文を見てください。

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

複数のターゲットを指定できるので、 'no'(少なくとも、指定したとおりにno)と指定することはできません。

9
ziya

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

second_argument := $(Word 2, $(MAKECMDGOALS) )
4
user5122888

それほど誇りに思っているわけではありませんが、環境変数を渡したくなかったので、既製のコマンドを実行する方法を逆にしました。

run:
    @echo command-you-want

これは実行したいコマンドを表示するので、サブシェルで評価してください。

$(make run) args to my command
3
Conrad.Dean

これが私の例です。私は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
osa

anonrun: ./progは右側がターゲットになるはずなので少し変に見えます、それでrun: progはよりよく見えます。

私は簡単にお勧めします:

.PHONY: run

run:
        prog $(arg1)

引数を渡すことができるということを付け加えたいと思います。

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

私が使用しているもう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
0
santon