web-dev-qa-db-ja.com

makefileで指定された依存関係をツリーとして表示する方法は?

問題

Makefileの1つ以上のターゲットの依存関係を確認したい。したがって、メイクファイルを解析して、依存関係をツリーのような形式(インデント、アスキーアートなど)またはグラフ(ドット、...)で表すことができるプログラムを探しています。

似ている

他の状況でこれを行うプログラムがあります。

  • pactree または debtree は、ソフトウェアパッケージの依存関係を、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=でさらに解析コードをハックする必要があるようです。そして、本当に完全なものになるかどうかはまだわかりませんこのようにしてグラフを修正します。

必要条件

いくつかの方法でグラフを制限するのはいいことです(組み込みルールなし、特定のターゲットのみ、一部の深さのみ)。しかし、大部分は、「合理的な」人間の依存関係を提供するツールを探しています-表示可能な形式( "Similar"のプログラムと同様)。

ご質問

  • これを行うことができるプログラムはありますか?
  • make -dnq ...から完全で正しい情報を入手できますか?
  • この情報を取得するより良い方法はありますか?
  • この情報を解析するためのスクリプト/試行はすでに存在していますか?
19
Lucas

同じ作者の makefile2graph を試してみてください。同様のツールがあります MakeGraphDependenciesJavaではなくcで書かれています。

make -Bnd | make2graph | dot -Tsvg -o out.svg

次に、いくつかのベクターグラフィックエディターを使用して、必要な接続を強調表示します。

10
xae

私は少なくとも、どのターゲットがどの前提条件に依存しているかについて、明確に構造化された情報を出力するための一種のハックを発見しました。欠点は、かなり煩わしいことです。つまり、すべてのターゲットのビルドレシピを小さな条件付き関数にラップするようにメイクファイルを変更する必要があります。簡単な例を掲載します。

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が(たとえば、環境変数として)設定されている場合にのみ発生します。この例では、ビルドレシピはターゲットがビルドされていることを示すエコーにすぎませんが、これを選択したコマンドに置き換えることは明らかです。

DEPENDENCY_GRAPHを1に設定すると、結果は次のようになります。

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

前の行の末尾のバックスラッシュを省略した場合、makeが文句を言う*** unterminated call to functioncall ':行方不明)'. Stop.誰かがmakeを使ってニースをプレイする方法を知っている場合、ぜひ聞きたいです。 :)

編集:このアプローチの他の問題は、makeが明らかに最新と見なされるターゲットのビルドレシピを実行しないため、ビルド結果が存在しない場合にのみ機能することです。

3
antred

私は remake --profilemakeのドロップイン置換)を使用しました、それはcallgrind形式で依存関係ツリーを生成しました。

次に gprof2dot を使用すると、ターゲットツリーのイメージを生成できます。

2

特定のターゲットの依存関係を一覧表示するだけの場合は、次のコマンドを使用できます。

make -dn MAKE=: you_target | sed -rn "s/^ *Considering target file '(.*)'\.$/\1/p"

MAKE=:は子makesを実行しないためのものです。

残念ながら含まれている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

再作成する必要がある依存関係のみをリストする必要がある場合は、 この回答 を参照してください。

0
anton_rh