BLOGTIMES
2010/07/02

gcc と gcov と カバレッジ

  c  softwareengineering 
このエントリーをはてなブックマークに追加

Javaで使えるカバレッジツールがありますか?と言われれればjcoverageとか、CloverEMMACoberturaあたりがすぐに思い浮かぶのですが、Cでといわれるとさっぱりです。ということで、Cでカバレッジを計測するツールを探すことになりました。

gcc には gcov というコマンドがついていた

Javaでもカバレッジ計測となるとかなり低レベルな部分で結構いろいろなことをしなくてはいけないので、C言語でそれをやるとなるとコンパイルの段階から細工しないといけないのだろうという察しはついたのですが、まったく取っ掛かりがなくて困りました。

ひとりあえず、Javaでお気に入りだったCoberturaをGoogleで探そうとして、間違ってCovertureと打ってしまったら、偶然gccでカバレッジが取れるという話を見つけてしまいました。このCovertureというツールもかなり気になりますが、これはひとまず脇に置いといて、もう少し詳しく調べてみるとgccにコンパイルオプションを加えて、gcovというツールを通すことでカバレッジを得られることが分かりました。

以下、具体的なカバレッジの取得メモです。

具体的なカバレッジの取り方

まず、下記のようなプログラムを用意します。見れば分かるとおり、このプログラムのFalse!を出力する部分の行は実行されないので、この部分が検出されるかどうかを確認してみます。

test.c

#include <stdio.h> int main(void) { int foo = 1; if( foo ){ printf("True !\n"); } else { printf("False !\n"); } return 0; }

コンパイル時には-coverageというオプション指定する必要があります。逆に言うとやることはこれだけでOKです。きちんと指定されていればコンパイル後に.gcnoというファイル(おそらく行番号などが保存されている?)が生成されているのが確認できます。

$ gcc -coverage test.c $ ls a.out test.c test.gcno

あとは普通にできた実行ファイルを起動してやります。実行後に.gcdaファイル(おそらくトレース情報が記録されている?)が生成されているのが確認できるはずです。これは実行されるごとにアップデートされるので、複数のテストケースを実行すればテストスイート全体でのC0カバレッジが取得できるようです。

$ ./a.out True ! $ ls a.out test.c test.gcda test.gcno

テストが実行し終わったら、最後にgcovを実行してやるとカバレージレポート(.gcovファイル)が出力されます。
標準出力にはカバレッジのサマリが出力されます。

$ gcov -bf test.c Function 'main' Lines executed:83.33% of 6 Branches executed:100.00% of 2 Taken at least once:50.00% of 2 Calls executed:50.00% of 2 File 'test.c' Lines executed:83.33% of 6 Branches executed:100.00% of 2 Taken at least once:50.00% of 2 Calls executed:50.00% of 2 test.c:creating 'test.c.gcov' $ ls a.out test.c test.c.gcov test.gcda test.gcno

カバレージレポートの中身は下記のようになっています。
-で始まる行は実行行でないことを示し、数字が入っている行はその行を何回実行したかを表します。実行行にもかかわらず一度も実行されていない行については#####が表示されています。基本的にはカバレージレポートから#####の行を探して、この部分をカバーするようなテストケースをテストスイートに追加するという作業を行うことになります。

$ cat test.c.gcov -: 0:Source:test.c -: 0:Graph:test.gcno -: 0:Data:test.gcda -: 0:Runs:1 -: 0:Programs:1 -: 1:#include <stdio.h> -: 2: function main called 1 returned 100% blocks executed 75% 1: 3:int main(void) { 1: 4: int foo = 1; 1: 5: if( foo ){ branch 0 taken 100% (fallthrough) branch 1 taken 0% 1: 6: printf("True !\n"); call 0 returned 100% -: 7: } else { #####: 8: printf("False !\n"); call 0 never executed -: 9: } 1: 10: return 0; -: 11:} -: 12:

思ったより簡単にC0カバレージを出力させることができました。

参考
  ・Gcov - Using the GNU Compiler Collection (GCC)
  ・gcov の使い方 - まめめも


    トラックバックについて
    Trackback URL:
    お気軽にどうぞ。トラックバック前にポリシーをお読みください。[policy]
    このエントリへのTrackbackにはこのURLが必要です→https://blog.cles.jp/item/3636
    Trackbacks
    このエントリにトラックバックはありません
    Comments
    愛のあるツッコミをお気軽にどうぞ。[policy]
    古いエントリについてはコメント制御しているため、即時に反映されないことがあります。
    コメントはありません
    Comments Form

    コメントは承認後の表示となります。
    OpenIDでログインすると、即時に公開されます。

    OpenID を使ってログインすることができます。

    Identity URL: Yahoo! JAPAN IDでログイン