94

特定の関数にヒットしているすべての可能な実行パスを見つけるための呼び出しグラフを生成しようとしています (この関数につながる多くのパスがあるため、すべてのパスを手動で把握する必要はありません) )。例えば:

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: ...

Codeviz と Doxygen を試してみましたが、どちらの結果もターゲット関数 D の呼び出し先しか表示されません。私の場合、D はオブジェクトがスマート ポインター内にラップされるクラスのメンバー関数です。クライアントは、D を呼び出すために、常にファクトリを介してスマート ポインター オブジェクトを取得します。

これを達成する方法を知っている人はいますか?

4

8 に答える 8

131
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

いくつかの光沢のある画像が得られます(main外部リンケージがあり、その翻訳単位の外部からも呼び出される可能性があるため、「外部ノード」があります):

コールグラフ

c++filt関連する関数とクラスのマングルされていない名前を取得できるように、これを で後処理することをお勧めします。以下のように

#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、定義が不明な関数によって呼び出されると想定されるプレースホルダーです。

于 2011-03-21T04:30:12.303 に答える
18

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

ここに画像の説明を入力

Johannes Schaub - litb main.cpp を使用すると、次のように生成されます。

ここに画像の説明を入力

おそらく、clang/opt よりも doxygen/dot の方がインストールと実行が簡単です。私はそれを自分でインストールすることができなかったので、別の解決策を見つけようとしました!

于 2015-12-03T10:28:27.830 に答える
11

正確な C++ コール グラフを静的に計算するのは困難です。正確な言語パーサー、正確な名前検索、および言語セマンティクスを適切に尊重する適切なポイント ツー アナライザーが必要だからです。Doxygen にはこれらのどれもありません。人々がなぜ C++ でそれを好むと主張しているのか、私にはわかりません。Doxygen が誤って解析する 10 行の C++ の例を作成するのは簡単です)。

コール グラフを動的に収集するタイミング プロファイラーを実行して(これは私たちのものを説明しています)、多くのケースを単純に実行する方がよい場合があります。このようなプロファイラーは、実行された実際のコール グラフを表示します。

編集:私は突然、呼び出しグラフを構築すると主張するC++ の理解を思い出し ました。彼らがパーサーに何を使用しているのか、または詳細な分析を正しく行っているのかどうかはわかりません。私は彼らの製品に関する具体的な経験がほとんどありません。私のいくつかの遭遇は、ポイントツー分析を行わないことを示唆しています。

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

于 2011-03-21T04:30:31.150 に答える
3

clang++コマンドが標準ヘッダー ファイルを検索するには、mpi.h2 つの追加オプションを使用する必要があります-### -fsyntax-only。つまり、完全なコマンドは次のようになります。

clang++ -### -fsyntax-only -S -emit-llvm main1.cpp -o - | opt -analyze -dot-callgraph
于 2014-07-03T14:09:32.633 に答える
1

「C++ Bsc アナライザー」は、bscmake ユーティリティによって生成されたファイルを読み取ることにより、コール グラフを表示できます。

于 2014-09-24T20:32:30.887 に答える