2024-02-28 makeで引数を渡す特定のテクニックに関する調査
今回の結論
makeの引数はターゲットを指定する部分なので、そこで引数を指定するやり方は少しトリッキーでおすすめできない。
また、%で存在しないtターゲットに対処するのは適切にエラーがおきなくなるのでバグの温床になる可能性をはらんでいる
普通に make targket HOGE=hogeといった引数で変数を変更できる仕組みを使うほうがよいのではないか
本題
makeで引数をわたすテクニックとしてでてきた以下の手法の評価したい。
code: make
args:
$(filter-out $@, $(MAKECMDGOALS)
%:
@:
この例は、make args echo hoge
とすると argsタスクを指定し、引数に渡したecho hogeを実行する。
echo と hogeというタスクがないためエラーになるためそれを抑制するための % タスクに と @: を割り当てている。
仕組み調査
MAKECMDGOARLS
MAKECMDGOARLSはmake にしていしたターゲットの情報をスペース区切りで持っている。つまり、 make args echo hogeを実行すると args echo hoge が束縛されている。
例 引数を出力する argsタスク
code: make
args:
echo $(MAKECMDGOALS)
%:
@:
code: shell
$ make args
echo args
args
code: sh
$ make -s args
args
code: sh
$ make -s args hoge
args hoge
code: sh
$ make -s args a b c d
args a b c d
ターゲットを空白区切りで持っているので不要なスペースはなくなっている。
特殊な用途のターゲットを含む場合に特殊処理に使う用途だと想像がつく。
$@
指定されたターゲット名が入る特殊変数
code: makefile
args:
echo %@
code:sh
$ make args
echo args
args
拡張子がcのものにマッチするタスクを用意し複数指定してみる
code: makefile
%.c:
echo $@
code: sh
$ make goro.c mogu.c
echo goro.c
goro.c
echo mogu.c
mogu.c
個別にマッチしそれぞれ違う値が入っている
filter-out pattern,text
textからpatternを含むものを削除する。filterの逆の動作をするためfilter-outのようだ。
例
code: make
filter-out:
echo $(filter-out aaa, aaa bbb)
code: sh
$ make filter-out
echo bbb
bbb
例
code: make
filter:
echo $(filter aaa, aaa bbb)
code: sh
$ make filter
echo aaa
aaa
%
どんなターゲットでもマッチするターゲットが作成できる。
例
code: makefile
aaa:
echo aaa
%:
echo bbb
ccc:
echo ccc
code: sh
$ make aaa
echo aaa
aaa
$ make bbb
echo bbb
bbb
$ make ccc
echo ccc
ccc
$ make ddd
echo bbb
bbb
bbb と ddd というターゲットは定義していないので、 %にマッチし bbb を出力している
@
makeは実行するコマンドをエコーする特性があるが@をつけることで抑制できる
例
code: make
aaa:
@echo aaa
code:sh
$ make aaa
aaa
:
何もしない組み込みコマンド( man bash で SHELL BUILTIN COMMANDSをみて)
code: sh
$ :
なにもおきません。
まとめると @ で:がエコーされず何もおきないということがおきている。
おまけ
make には複数のターゲットを指定する仕組みがある
code: make
aaa:
echo aaa
bbb:
echo bbb
code: sh
$ make aaa bbb
echo aaa
aaa
echo bbb
bbb
$ make bbb aaa
echo bbb
bbb
echo aaa
aaa
別の方法検討]
make には make変数をコマンドラインから指定する方法がある
例
code: make
BODY = body
aaa:
echo $(BODY)
code: sh
$ make aaa BODY=goro
echo goro
goro
$ make aaa
echo body
body
素直にこちらを使ったほうが安全そうである。