1. ホーム
  2. メイクファイル

[解決済み】makefileでターゲットのリストを取得する方法とは?

2022-04-19 12:42:17

質問

私は rake (Ruby の make プログラム) を少し使っていますが、利用可能なターゲットのリストを取得するオプションがあります。

> rake --tasks
rake db:charset      # retrieve the charset for your data...
rake db:collation    # retrieve the collation for your da...
rake db:create       # Creates the databases defined in y...
rake db:drop         # Drops the database for your curren...
...

が、GNU make にはこれを実行するオプションがないようです。

どうやら2007年の時点で、そのためのコードはほぼ完成しているようです -。 http://www.mail-archive.com/[email protected]/msg06434.html .

とにかく、makefile からターゲットを抽出するための小さなハックを作って、それを makefile に含めることができるようにしました。

list:
    @grep '^[^#[:space:]].*:' Makefile

定義されたターゲットのリストが表示されます。これは単なる手始めであり、例えば依存関係をフィルタリングすることはできません。

> make list
list:
copy:
run:
plot:
turnin:

解決方法は?

を改善する試みです。 Brent Bradburnの素晴らしいアプローチ を以下のように設定しました。

  • はターゲット名を抽出するためのより堅牢なコマンドを使用しており、うまくいけば誤検出を防ぐことができます (また、不要な sh -c )
  • にある makefile を必ずターゲットにするわけではありません。 現在 で明示的に指定されたメイクファイルを尊重します。 -f <file>
  • 隠しターゲットを除外する - 慣例により、これらは名前が文字または数字で始まらないターゲットである。
  • を使用します。 シングル ニセモノのターゲット
  • はコマンドの先頭に @ 実行前にエコーされないようにするため

不思議なことに、GNU make をリストアップする機能はありません。 ちょうど は、makefile で定義されたターゲットの名前です。一方 -p オプションはすべてのターゲットを含む出力を生成しますが、他の多くの情報の中に埋もれてしまい、またデフォルトターゲットも実行されます (このターゲットは -f/dev/null ).

GNU用のmakefileに以下のルールを記述してください。 make という名前のターゲットを実装するために list として起動し、すべてのターゲット名をアルファベット順に並べるだけです。 make list :

.PHONY: list
list:
    @LC_ALL=C $(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$'

重要 : これを貼り付けるにあたって 最後の行がインデントされていることを確認してください。 タブ文字1文字分 (スペースは ない 仕事) .

注意点 ソート を使用するのが最適です。 ない のソートでは、ターゲットが makefile に現れる順番が ではない を保存します。

また、複数のターゲットで構成されるルールのサブターゲットは必ず出力される 別々に であり、したがって、ソートにより、通常は ない で始まるルールは、隣り合わせに表示されます。 a z: ない ターゲットを持つ az 記載されている 隣同士 が出力されます。

ルールの説明 :

  • . PHONY: list

    • ターゲットリストがニセモノであることを宣言しています。 ない を参照している。 ファイル そのため、そのレシピを呼び出す必要があります。 無条件に
  • LC_ALL=C を確認します。 make の出力は 英語 出力の解析はそれに依存しているからです。 に脱帽。 バスティアン・ビトルフ

  • $(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null

    • 起動する make Makefile から派生したデータベースを出力し、パースするために、もう一度。
      • -p データベースを表示します。
      • -Rr 組み込みルールや変数のインクルードを抑制する
      • -q はターゲットの最新状態をテストするだけですが(何も作り直さない)、それ自体はすべてのケースでレシピコマンドの実行を妨げるわけではありません。
      • -f $(lastword $(MAKEFILE_LIST)) で暗黙的にターゲットにしたか明示的にターゲットにしたかに関わらず、 元の呼び出しと同じ makefile がターゲットになることを保証します。 -f ... .

        洞窟 : この場合、makefile に include ディレクティブを定義します。 THIS_FILE := $(lastword $(MAKEFILE_LIST)) 以前 いずれか include ディレクティブを使用し -f $(THIS_FILE) の代わりに
      • : 意図的に無効なターゲット を意味するものです。 コマンドが実行されないようにする ; 2>/dev/null は、結果として生じるエラーメッセージを抑制します。注意:これは -p にもかかわらず、データベースを印刷することは、GNU make 3.82の時点ではそうなっています。悲しいことに、GNU makeは以下のような直接のオプションを提供していません。 ただ を使わずに、データベースを印刷します。 また はデフォルトの (あるいは指定された) タスクを実行します。特定の Makefile をターゲットにする必要がない場合は make -p -f/dev/null で推奨されているように man のページをご覧ください。
  • -v RS=

    • これは、入力を連続した空行でないブロックに分割する awk のイディオムです。
  • /^# File/,/^# Finished Make data base/

    • すべてのターゲットを含む出力の行の範囲にマッチします (GNU make 3.82 では真)- 解析をこの範囲に限定することで、他の出力セクションからの誤検出を扱う必要がなくなります。
  • if ($$1 !~ "^[#.]")

    • ブロックを選択的に無視する。
      • # で始まるブロックを持つ非ターゲットを無視します。 # Not a target:
      • . ... 特殊なターゲットを無視する
    • 他のすべてのブロックは、それぞれ明示的に定義されたターゲットの名前だけを含む行で始まり、その後に :
  • egrep -v -e '^[^[:alnum:]]' -e '^$@$$' は、出力から不要なターゲットを削除します。

    • '^[^[:alnum:]]' ...除外する 隠された ターゲットとは、慣習上、文字や数字で始まらないターゲットのことです。
    • '^$@$$' ... は除外されます。 list ターゲットそのもの

実行中 make list を実行すると、すべてのターゲットがそれぞれの行に表示されます。 にパイプすることができます。 xargs を使えば、スペースで区切られたリストを作成することができます。