
問題
私は、makefile の 1 つ以上のターゲットの依存関係を確認したいと考えています。そのため、makefile を解析して、依存関係をツリーのような形式 (インデント、ASCII アートなど) またはグラフ (ドットなど) で表すことができるプログラムを探しています。
似ている
他の状況でもこれを行うプログラムがあります:
- パクツリーまたは債務不履行ソフトウェアパッケージの依存関係を、ASCII形式のようなツリー形式または
dot
グラフ形式で表示できます。 gcc -M source_file.c
Cソースファイルの依存関係をmakeルールとして表示します。- pstreeプロセス ツリーの ASCII 表現を表示します。
進捗
ウェブを検索して見つけた少しの助けそれが私を試してみるきっかけとなった
make --always-make --silent --dry-run some_target | \
grep --extended-regexp 'Considering target file|Trying rule prerequisite'
しかし、これを素敵なツリー/グラフとして表現するには、Perl または Python でさらに解析コードをハックする必要があるようです。また、この方法で完全かつ正しいグラフを本当に取得できるかどうかはまだわかりません。
要件
グラフを何らかの方法で制限できればよいのですが (組み込みルールなし、指定されたターゲットのみ、深さのみ)、ほとんどの場合、依存関係を「合理的」で人間が表示できる形式 (「類似」のプログラムのように) で提供してくれるツールを探しています。
質問
- これを実行できるプログラムはありますか?
- から完全かつ正確な情報を入手できますか
make -dnq ...
? - この情報を取得するより良い方法はありますか?
- この情報を解析するためのスクリプトや試みはすでに存在しますか?
答え1
試すメイクファイル2グラフ同じ作者による同様のツールがあるグラフ依存関係を作成するjava
の代わりにで記述しますc
。
make -Bnd | make2graph | dot -Tsvg -o out.svg
次に、ベクター グラフィック エディターを使用して、必要な接続を強調表示します。
答え2
私はリメイク --プロフィール( のドロップイン代替make
) は、callgrind 形式で依存関係ツリーを生成しました。
それからgprof2dot対象ツリーの画像を生成できます。
答え3
私は、少なくともどのターゲットがどの前提条件に依存しているかについて、明確に構造化された情報を出力する一種のハックを見つけました。欠点は、それが非常に煩わしいことです。言い換えると、すべてのターゲットのビルド レシピを小さな条件関数にラップするように、makefile を変更する必要があります。簡単な例を投稿します。
getRecipe = $(if $(DEPENDENCY_GRAPH),@echo Target $@ depends on prerequisites "$^",$(1))
VARIABLE_TARGET_NAME = foobar.txt
all : TopLevelTarget
TopLevelTarget : Target_A Target_D
$(call getRecipe,\
@echo Building target $@)
Target_A : Target_B
$(call getRecipe,\
@echo Building target $@)
Target_D : Target_C
$(call getRecipe,\
@echo Building target $@)
Target_B : $(VARIABLE_TARGET_NAME)
$(call getRecipe,\
@echo Building target $@)
Target_C :
$(call getRecipe,\
@echo Building target $@)
$(VARIABLE_TARGET_NAME) :
$(call getRecipe,\
@echo Building target $@)
この例では、手動で作成した getRecipe 関数を使用して、各ターゲットのレシピをラップし、そのレシピを実際に実行するか、ビルドされているターゲットとそれが依存する前提条件を単に出力するかを決定します。後者は、変数がDEPENDENCY_GRAPH
設定されている場合にのみ発生します (たとえば、環境変数として)。この例では、ビルド レシピはターゲットがビルドされていることを示すエコーにすぎませんが、もちろん、これを任意のコマンドに置き換えることができます。
1 に設定するとDEPENDENCY_GRAPH
、出力は次のようになります。
Target foobar.txt depends on prerequisites ""
Target Target_B depends on prerequisites "foobar.txt"
Target Target_A depends on prerequisites "Target_B"
Target Target_C depends on prerequisites ""
Target Target_D depends on prerequisites "Target_C"
Target TopLevelTarget depends on prerequisites "Target_A Target_D"
これは解析してドットグラフに変換するのが簡単なはずです。
DEPENDENCY_GRAPH
まったく設定されていないか 0 に設定されている場合、出力は次のようになります。
Building target foobar.txt
Building target Target_B
Building target Target_A
Building target Target_C
Building target Target_D
Building target TopLevelTarget
言い換えれば、代わりに通常のビルド レシピが使用されます。複雑なレシピでこれが確実に機能するかどうかはまだテストしていません。すでに遭遇した問題の 1 つは、複数行のレシピではまったく機能しないということです。
たとえば、最後のターゲットのビルド レシピでは、ターゲットがビルド中であることに加えて、実際にtouch
次のファイルが必要でした。
$(VARIABLE_TARGET_NAME) :
$(call getRecipe,\
@echo Building target $@\
touch $@)
make
touch $@
この部分は、前の行のエコーの一部に過ぎないと考えているようです。
Building target foobar.txt touch foobar.txt
前の行の末尾のバックスラッシュを省略すると、「call': missing」というエラーが発生します。これをうまく動作させる方法を誰か知っている方がいたら、ぜひ教えてください。make
:)*** unterminated call to function
)'. Stop.
make
編集: このアプローチのもう 1 つの問題は、ビルド結果がまだ存在しない場合にのみ機能することです。これは、make
最新であるとみなされるターゲットのビルド レシピが実行されないことは明らかです。
答え4
特定のターゲットの依存関係を一覧表示する必要がある場合は、次のコマンドを使用できます。
make -dn MAKE=: you_target | sed -rn "s/^ *Considering target file '(.*)'\.$/\1/p"
MAKE=:
走らない子供のための作る。
残念ながら、含まれているMakefileもリストされています。それらを除外する次のシェルスクリプトを使用します ( list-deps
):
#!/bin/sh -e
dbg="`make -dn "$@"`"
all="`echo -n "$dbg" | sed -rn "s/^ *Considering target file '(.+)'\.$/\1/p"`"
mks="`echo -n "$dbg" | sed -rn "s/^ *Reading makefile '([^']+)'.*$/\1/p"`"
echo -n "$all" | grep -vxF "$mks"
次のコマンドを使用して、ターゲットのすべての依存関係を一覧表示できます。
list-deps MAKE=: your_target
再作成が必要な依存関係のみをリストする必要がある場合は、この答え。
編集:この回答を見つけた他の人のために - インデントを維持するには、
make -dn MAKE=: you_target | sed -rn "s/^(\s+)Considering target file '(.*)'\.$/\1\2/p"
これを Makefile のターゲットにすることもできます:
.PHONY: graph
graph:
make -dn MAKE=: all | sed -rn "s/^(\s+)Considering target file '(.*)'\.$/\1\2/p"