2011-03-21 29 views
64

私は、特定の関数を実行しているすべての可能な実行パスを見つけるための呼び出しグラフを生成しようとしています(手動ですべてのパスを調べる必要はありませんこの機能につながる多くの経路があります)。例えば:私はCodevizとDoxygenのを試してみましたC++コードの呼び出しグラフを生成する

path 1: A -> B -> C -> D 
path 2: A -> B -> X -> Y -> D 
path 3: A -> G -> M -> N -> O -> P -> S -> D 
... 
path n: ... 

、何とか両方の結果は、ターゲット関数の呼び出し先が、何も表示されない、私の場合はD.は、Dは、オブジェクトスマート以内にラップされるクラスのメンバ関数でありますポインタ。クライアントは常にDを呼び出すためにファクトリを介してスマートポインタオブジェクトを取得します。

これを達成する方法を知っている人はいますか? (mainが外部結合を有し、あまりにもその翻訳単位外部から呼び出される可能性があるため、「外部ノード」がある)

答えて

95
static void D() { } 
static void Y() { D(); } 
static void X() { Y(); } 
static void C() { D(); X(); } 
static void B() { C(); } 
static void S() { D(); } 
static void P() { S(); } 
static void O() { P(); } 
static void N() { O(); } 
static void M() { N(); } 
static void G() { M(); } 
static void A() { B(); G(); } 

int main() { 
    A(); 
} 

そして

$ clang++ -S -emit-llvm main1.cpp -o - | opt -analyze -dot-callgraph 
$ dot -Tpng -ocallgraph.png callgraph.dot 

は、いくつかの光沢のある画像が得られる:

Callgraph

これをc++filtで後処理したい場合は、次のようにunmangledな名前を得ることができますe関数とクラスが含まれています。次

#include <vector> 

struct A { 
    A(int); 
    void f(); // not defined, prevents inlining it! 
}; 

int main() { 
    std::vector<A> v; 
    v.push_back(42); 
    v[0].f(); 
} 

$ clang++ -S -emit-llvm main1.cpp -o - | 
    opt -analyze -std-link-opts -dot-callgraph 
$ cat callgraph.dot | 
    c++filt | 
    sed 's,>,\\>,g; s,-\\>,->,g; s,<,\\<,g' | 
    gawk '/external node/{id=$1} $1 != id' | 
    dot -Tpng -ocallgraph.png  

で神秘的な無名の機能、Node0x884c4e0は、と仮定プレースホルダであることを(私のオハイオ州、最適化せずにサイズがオンになってあまりにも大きかったです!)

Beauty

を、この美しさを生み出すのように定義がわからない関数によって呼び出されます。

+17

あなたは、複数のファイルをプロジェクトにこれを行っていますか?ツールとして非常にクールに見える – dirvine

+0

これを行う方法がありますので、互いに呼び出すすべてのstd関数のようなファイル/ファイルに対してローカルではない関数は呼び出されません。 – soandos

+2

+1なんらかの理由で、名前を解くために-nオプションをC++ filtに渡さなければなりませんでした。他の誰かが同じ問題に直面した場合、私はここでそれを言及したいと思った。 – Aky

3

正確なC++呼び出しグラフを静的に計算するのは難しいのです。正確な言語パーサ、正しい名前検索、言語セマンティクスを適切に尊重するポイントツーアナライザが必要なためです。 Doxygenはこれらのどれも持っていませんが、人々がC++のためにそれを好きだと主張する理由はわかりません。 Doxygenが誤って分析する10行のC++の例を構築するのは簡単です)。

timing profiler which collects a call graph dynamicallyを実行する方が良い場合があります(これは私たちの説明です)、単純に多くのケースを実行します。このようなプロファイラは実際に実行されたコールグラフを表示します。

EDIT:私は突然、コールグラフの作成を主張するUnderstand for C++を思い出しました。私は彼らがパーサのために何を使うのか、彼らが詳細な解析権を持っているのかどうかはわかりません。私は彼らの製品に関して特別な経験はありません。

私はClaNを使ってSchaubの答えに感銘を受けました。私はClangがすべての要素を正しく持っていると期待しています。

clang++ -### -fsyntax-only -S -emit-llvm main1.cpp -o - | opt -analyze -dot-callgraph 
+0

残念ながら、私はその機能を引き起こす可能性のあるすべてのユースケースを認識していません:(実際には、私の最終目標はデバッグ目的でその機能を利用するユースケースの正確なリストを見つけることです。コードインデックスツールを使用して直接の呼び出し元を見つけることができますが、さらに分析するためにすべての実行パスを把握する必要があります。 – shiouming

3

は、-### -fsyntax-onlyを使用する必要があります - bscmakeユーティリティーで生成されたファイルを読み取る。

1

「C++ BSC Analyzerは、」グラフを呼び出して表示することができます:完全なコマンドはようになります。すなわちmpi.h 2つの追加オプションなどの標準ヘッダファイルを検索するclang++コマンドのために

11

これを実現するには、doxygen(グラフ生成用にドットを使用するオプション付き)を使用します。

ヨハネス・シャウブと

enter image description here

- litb main.cppに、それが生成し、この:

enter image description here

ました。doxygen /ドットはおそらく打ち鳴らすの/ optにインストールして実行するよりも簡単です。私はそれを自分でインストールすることはできませんでした。そのため、私は代替の解決策を見つけることを試みました!

+1

doxygenを実行してあなたが含むウィンドウを取得する方法の例を追加できますか? –

+0

@nimble_ninja:doxywizardの設定ダイアログのスクリーンショットは十分ではありませんか? – jpo38

+0

私はそれがdoxywizardからであることを知らなかった。ありがとう! –

3

あなたはCppDependを使用することができ、それはグラフ

  • 依存関係グラフ
  • コールグラフ
  • クラスの継承グラフ
  • カップリンググラフ
  • パスグラフ
  • すべてのパスの多くの種類を生成することができますグラフ
  • サイクルグラフ

enter image description here

関連する問題