質問

質問

質問

makefileの1つ以上のターゲットへの依存関係を見たいです。だから私はmakefileを解析し、いくつかのツリー形式(インデント、ascii-artなど)またはグラフィック(ドット、...)で依存関係を表現できるプログラムを探しています。

似たような

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

  • パークツリーまたは借金の木dotその形式のソフトウェアパッケージの依存関係は、ツリー形式(ASCII形式など)またはグラフィックとして表示できます。
  • gcc -M source_file.cC ソースファイルの依存関係を make ルールで表示します。
  • プロセスツリーのASCII表現を表示します。

進展

私が見つけたウェブ検索中あまり役に立たない。これが私に試してみました。

make --always-make --silent --dry-run some_target | \
  grep --extended-regexp 'Considering target file|Trying rule prerequisite'

しかし、これを素晴らしいツリー/グラフで表現するには、PerlやPythonで解析コードをもう少し解読する必要があるようです。このように、実際に完全で正確な図が得られるかどうかはまだわかりません。

必要

どのような方法でもチャートを制限したいのですが(デフォルトの提供ルールはありません、与えられた目標のみ、特定の深さのみ)、ほとんどの場合、「合理的な」ものを提供するツールを探しています。依存関係 - 表示できる形式です(「類似」以下のプログラムと同じ)。

質問

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

答え1

努力するmakefile2graph同じ著者の同様のツールがあります。MakeGraphの依存関係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ゼロに設定すると、出力は次のようになります。

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 $@)

maketouch $@この部分は前の行のエコーの一部であるようです。

Building target foobar.txt touch foobar.txt

前の行で末尾のバックスラッシュを省略すると、「: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" 

関連情報