makefileにhelpを付けるワンライナー
makeファイルはデフォルトではhelpが存在しない。bashの補完の設定などを入れているとタブで利用可能なタスクの一覧が出る環境もあるが、その設定もしていない場合には利用可能なタスクの一覧も表示できない。
タスクに対するcommentの流派
似たようなことを考える人はいるもので、help
というタスク(ターゲット)を定義してhelpメッセージを表示しようという試みをしている人たちがいる。
ちょっとだけ検索してみた所以下の2つの流派があるみたい。
<task>: ## <comment>
派
- https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html (和訳)
- https://qiita.com/po3rin/items/7875ef9db5ca994ff762
- https://gist.github.com/prwhite/8168133
- https://nedbatchelder.com/blog/201804/makefile_help_target.html
## <comment>\n<task>:
派
<task>: ## <comment>
派が多いように見えたけれど、概ね元となる一番上の記事のコピーのようだった。
雰囲気
前者は(<task>: ## <comment>
派) 以下の様に書く形。依存するターゲットがあった場合には ##
の前に書く。
task0: ## comment of task0 .. do something task1: ## comment of task1 .. do something task2: task0 task1 ## comment of task2 .. do something
後者(## <comment>\n<task>:
派)は以下の様に書く形。依存の記述方法で特に気をつけることは存在しない。
## comment of task0 task0: .. do something ## comment of task1 task1: .. do something ## comment of task2 task2: task0 task1 .. do something
個人的には、後者(## <comment>\n<task>:
派)の方が良いのだけれど。これを導入するために新たなコマンドのインストールが必要というのは微妙だなーと思ったりした。
.DEFAULT_GOAL
と MAKEFILE_LIST
ちなみにこれはtips的な話だけれど。両者は共に.DEFAULT_GOAL
と MAKEFILE_LIST
を使っている。
.DEFAULT_GOAL
.DEFAULT_GOAL
は引数無しで make
を実行した時に実行されるターゲットのこと。
.DEFAULT_GOAL := bar foo: @echo foo bar: @echo bar
ちなみにこれは、-p
(--print-data-base
)オプションで調べられる
$ make -p | grep -i default_goal .DEFAULT_GOAL := bar
そして通常は先頭のタスク。
--- 00defaultgoal/Makefile 2019-04-15 21:58:29.207999840 +0900 +++ 01defaultgoal/Makefile 2019-04-15 21:58:24.384597546 +0900 @@ -1,5 +1,3 @@ -.DEFAULT_GOAL := bar - foo: @echo foo bar:
.DEFAULT_GOAL := bar
の指定がない時にはfoo
$ make -p | grep -i default_goal .DEFAULT_GOAL := foo
MAKEFILE_LIST
これはmakeで渡されたファイルのこと。通常はMakefile
なりmakefile
などが入る。ファイル名を気にせずタスクを記述できるようになっている。
build.mk
default: echo @@ $(MAKEFILE_LIST) @@
例えば以下の様に -f
付きでファイルを指定したときなどに値が変わる。
$ make -f build.mk echo @@ build.mk @@ @@ build.mk @@
ちなみに同様のものとして $(MAKE)
というものもある。
## <comment>\n<task>:
をワンライナーで
個人的には ## <comment>\n<task>:
の方がMakefileとしては扱いやすい気がするので好みなのだけれど、気持ちparseするのが面倒なので正直な所unixのコマンドの範囲だとツライ。なにかテキトーなLLでのワンライナーでやってしまいたくなる。
このあたりになるとお里が知れるという感じになるかもしれない。
python自体はワンライナーに向いている言語ではないけれど、慣れているのでpythonでやってみる。rubyで言うeash_consに似たものを作るのにitertoolsのteeとchainを使うのはかなりオーバーエンジニアリング(?)感がある。まぁどこにでもpythonくらいは入っていそうなので。
help: @cat $(MAKEFILE_LIST) | python -u -c 'import sys; import re; from itertools import tee,chain; rx = re.compile(r"^[a-zA-Z0-9\-_]+:"); xs, ys = tee(sys.stdin); xs = chain([""], xs); [print(f"""\x1b[36m{line.split(":", 1)[0]:20s}\x1b[0m\t{prev.lstrip("# ").rstrip() if prev.startswith("##") else "" }""") for prev, line in zip(xs, ys) if rx.search(line)]'
一応こんな感じで表示される様になる。
ちなみに個人的にはソートされずにファイルに記述された順序でhelpメッセージが出るほうが好きだったりします。