

過去のソフトの解析を現在行っているのですが  
関数の呼び出しをリスト化するアプリは無いでしょうか

doxygenでコールグラフは作れたのですがあまりに入り組んでいて、書類化出来ないので  
csv等で出力したいです(csvに限らずとにかくリスト化できればいいです)

fooa->foob->fooc1  
->fooc2

という呼び出しだったら  
fooa,foob,fooc1  
,,fooc2

のように出力するソフトを探しています  
無意味に再帰していたり、関数のコールがループしたりしていたりするのでそれもマークをつけてくれると嬉しいですが  
とにかくリスト化できるようなアプリがあったら教えてください


CC BY-SA 4.0
2018-08-09T06:52:12.530
47373
2020-07-13T02:04:00.357
2018-08-09T09:51:26.480
19110
15047
question
c
過去のソフトの解析として、関数呼び出しの関係を可視化したい


残念ながら巨大なステップ数の場合は、既存のツールではほぼ役に立ちません。  
自分の場合は、Perlで２つの簡単なスクリプトを作りました。  
**その１）ソースから'('を検出して次のようなリスト１を出力するスクリプト１**  
\---< リスト１  
＜関数名＞:＜その関数内で使用されている関数名＞  
...  
\---  
※お好みで予めプリプロセッサを通しておくと良いかも。

**その２）リスト１を辿って次のようなリスト２を出力するスクリプト２**  
\---< リスト２  
＜関数名１＞：＜関数名２＞：＜関数名３＞...  
...  
\---  
※「関数１から関数２を呼び出していて、更に関数２から関数３を呼び出す」を意味している。  

リスト１ができると逆に親は誰か調べることで、ある関数に変更を加えた場合の上位から見た影響範囲を調べることができて重宝します。  
これらのスクリプトは瞬間にリストが得られますし、既存ソースの問題点が発見できたりとメリットが非常に多いです。  
そうした理由から、自分で使うツールは自分で作ることをお勧めします。  
また、無料で入手できるツールは「何があっても責任を持たない」と言ったものばかりなので使用は避けるべきです。


CC BY-SA 4.0
2018-12-17T01:40:05.817
51276
2018-12-17T02:14:39.190
2018-12-17T02:14:39.190
3060
31474
47373
answer


user29553さんのコメントにありますが、cflowがいいと思います。  
結果をCSVに整形してみました。

【awkによる整形の例(call_stack.sh)】

[code]

    #!/bin/bash
    while read file; do cflow ${file}; done | sed '
    s/    /\t/g
    s/) /)\t/
    ' | awk -F '\t' '
    BEGIN{
            ##DELIMITER = "->"
            DELIMITER = ","
    }
    {
            num = NF;
            for(no = 1; no <= num; no++){
                    if($no != ""){
                            if(!match($no, "^<")){
                                    ga[no] = $no
                            }
                            else{
                                    if(match($no, "recursive:")){
                                            ga[no-1] = ga[no-1] "*";
                                    }
                                    delete ga[no];
                                    num -= 1;
                            }
                    }
            }
            dlmt = ""
            call_stack = "";
            for(no = 1; no <= num; no++){
                    call_stack = call_stack dlmt ga[no]
                    dlmt = DELIMITER
            }
            printf("%s\n", call_stack);
    }
    '
    
    
[/code]

【使い方】

[code]

    find . -name "*.c" | ./call_stack.sh
    
    
[/code]

【実行結果】  
単純な再帰呼び出しはcflowが検出してくれるので、関数に`*`をマークしました。

[code]

    func()
    func(),printf()
    func(),func2()
    func(),n_sub()
    func(),n_sub(),func3()
    func(),n_sub(),printf()
    func(),func()*
    func2()
    func2(),printf()
    func2(),n_sub()
    func2(),n_sub(),func3()
    func2(),n_sub(),printf()
    func2(),func()
    func3()
    func3(),printf()
    func3(),func2()
    func3(),n_sub()
    func3(),n_sub(),printf()
    main()
    main(),printf()
    main(),n_sub()
    main(),n_sub(),printf()
    main(),func()
    main(),func2()
    
    
[/code]

【cflowの出力(参考)】

[code]

    for file in *.c; do cflow  ${file}; done
    
[/code]

[code]

    func() <int func () at func.c:7> (R):
        printf()
        func2()
        n_sub() <int n_sub () at func.c:14>:
            func3()
            printf()
        func() <int func () at func.c:7> (recursive: see 1)
    func2() <int func2 (void) at func2.c:7>:
        printf()
        n_sub() <int n_sub () at func2.c:13>:
            func3()
            printf()
        func()
    func3() <int func3 () at func3.c:5>:
        printf()
        func2()
        n_sub() <int n_sub () at func3.c:11>:
            printf()
    main() <int main (int argc, char *argv[]) at main.c:6>:
        printf()
        n_sub() <int n_sub () at main.c:13>:
            printf()
        func()
        func2()
    
    
[/code]

【使用したツール】

cflow (GNU cflow) 1.4  
sed (GNU sed) 4.4  
GNU bash, バージョン 4.4.20(1)-release (x86_64-pc-linux-gnu)  
GNU Awk 4.1.4, API: 1.1 (GNU MPFR 4.0.1, GNU MP 6.1.2)

【おまけ】

ClangのPython bindingを使うと、C言語のソース解析がとても楽にできます。  
※ 関数の呼び出し関係を調べるだけならcflowの方が簡単です。


CC BY-SA 4.0
2019-09-16T03:19:05.503
59090
2019-09-16T03:19:05.503
35558
47373
answer