モダンなC, C++の開発環境の構築方法

まだC, C++がないようなので書いてみた。主にLinux(DebianとかUbuntu)での環境構築について。

コンパイラ

まずはapt-getでコンパイラをインストールする。UbuntuやDebianなら以下のコマンドでgccやg++および標準ライブラリ等がインストールされる。

$ sudo apt-get install build-essential

デバッグツール

デバッガおよびデバッグツールは少なくとも以下の三つは入れる。(あとltraceも欲しいかな?)

$ sudo apt-get install gdb valgrind strace

ビルドツール

C, C++のビルドツールといえばまずmakeが浮かぶけど、最近ではSConsやCMakeなどの代替ツールでビルドするOSSを見かけることが増えてきた感がある。とはいえ、依然としてビルドにmakeが必要なプロジェクトはたくさんあるので、とりあえずmakeは入れる。

$ sudo apt-get install make
makeの代替としてのSCons

SConsは数多くあるmakeの代替ツールのうちの一つ。makeではファイル間の依存関係を自分で記述する必要があるけど、SConsだと各ファイルの依存関係の解析を実行時に自動的に行ってくれるので、ビルドファイルがMakefileに比べてシンプルになるという利点がある。またビルドファイルをPythonで記述できるので、Makefileに比べてかなり融通の利く描き方ができる。SConsの簡単なチュートリアルについてはこちら。
DebianやUbuntuならapt-getで簡単にインストールできる。

$ sudo apt-get install scons

テスト

CならCUnit、C++ならgoogletestがオススメ。ほかにもCppUnitがあるけど、何というかあれはCUnitをものすごく書きにくくしたような物に仕上がっているので、個人的にオススメできない。

$ sudo apt-get install libcunit1 libcunit1-dev # CUnit
$ sudo apt-get install libgtest0 libgtest-dev  # googletest

テストカバレッジ

テストカバレッジにはgcovを使う。これはGCCに組み込まれているものと考えていい。

$ gcc -coverage -o prog prog.c
$ ./prog
$ gcov prog.gcda
File 'prog.c'
Lines executed:87.25% of 102
$

上記の通りにコマンドを実行するとprog.gcovというファイルができる。また、この場合のカバレッジ率は87.25%になっている。gcovの中身は以下のような感じ。「#」で始まっている行が実行されていない(テストできていないこと)を表している。

     6146:  154:    for (int i=0;i<c;++i) {
     6139:  155:        fnv_ent_t *tail = ents[i].next;
    12366:  156:        while (tail) {
       88:  157:            fnv_ent_t *current = tail;
       88:  158:            tail = tail->next;
       88:  159:            FNV_FREE(current);
        -:  160:        }
        -:  161:    }
        7:  162:    FNV_FREE(tbl);
        7:  163:}
        -:  164:
        -:  165:/**
        -:  166: * print entries of hash table
        -:  167: */
    #####:  168:void fnv_tbl_print(fnv_tbl_t *tbl, size_t c) {
    #####:  169:    fnv_ent_t *ents = tbl->ents;
    #####:  170:    for (int i=0;i<c;++i) {
    #####:  171:        fnv_ent_t *ent = &ents[i];
    #####:  172:        if (ent->k == NULL) continue;
    #####:  173:        printf("i = %d, key = %s, val = %s", i, ent->k, (char *)ent->v);
    #####:  174:        if (ent->next != NULL) {
    #####:  175:            fnv_ent_t *tail = ent->next;
    #####:  176:            while (tail) {
    #####:  177:                printf(" -> key = %s, val = %s", tail->k, (char *)tail->v);
    #####:  178:                tail = tail->next;
        -:  179:            }
        -:  180:        }
    #####:  181:        printf("\n");
        -:  182:    }
    #####:  183:}

プロファイラ

C, C++のプロファイラだとgprofあるいはgoogle-perftools等がある。(追記:gprofはoprofileではなくbinutilsをインストールする。 2010/8/1 12:10)

$ sudo apt-get install binutils # gprof(最初から入ってるかも)
$ sudo apt-get install libgoogle-perftools0 libgoogle-perftools-dev # google-peftools

各々の簡単な使い方については、gprofはこちらが、google-perftoolsはこちらがわかりやすい。

ソースコード索引

C, C++のソースコード索引にはGNU GLOBALがオススメ。etagsやctagsにはない複数候補への対応や定義元だけでなく参照元へのジャンプや検索をサポートしているのがとても便利。あとエディタに依存しない。Emacs使いならgtags.el、vim使いならgtags.vimをインストールしよう。この二つのファイルはGNU GLOBALのソースコードに含まれている。

$ sudo apt-get install global

索引を生成するにはソースコードがあるディレクトリでgtagsコマンドを実行する。

$ gtags -v # -v:verbose

gtagsは既に索引があるかどうかに関わらず最初から索引を全部作り直すので、既にある索引を更新する場合はglobalコマンドに-uを付加して実行する。

$ global -uv # -v:verbose

パッケージシステム

C, C++においてPerlのCPANやRubyのgems、PHPのPEARに相当するパッケージシステムは存在しない。でもまあ基本的に開発に最低限必要なパッケージはyumとかaptで十分カバーできるので、特に困らない。むしろ複数のパッケージシステム(yumとPEARとか)をごちゃ混ぜに扱ったり、統一するためにrpmやdebパッケージをいちいち作らなければいけないケースはLLに比べて少ないと思う。

自動ドキュメント化ツール

C, C++だとDoxygenしか思い浮かばないんだけど、ほかにもあるんだろうか?

$ sudo apt-get install doxygen

たまにはGCC以外でもビルドしてみよう

僕は普段からLinux上でほぼCUIなターミナルで開発しているけど、自分が作ってるライブラリの動作確認のためにWindows7(64bit版)を立ち上げてVisual Studioでビルドすることがたまにある。LinuxやMacでは問題なく動いていたのにWindowsだとそもそもコンパイルが通らないというケースもある。*1それに開発者がWindows上での動作を完全には保証しない方針を採っているのだとしてもVisual Studioはコンパイラのチェックが(デフォルトの)GCCに比べて厳しいので、プログラムをVisual Studioのコンパイラに通すだけでもプログラムの潜在的なリスクを検出するのには役立つ。GCCでも適切に複数のオプションを付加すればいいんだろうけど、真面目に付加していくと結構な量になるし、すべての警告オプションを付けるのもアレなので、自分が必要だと思うオプションを適宜付加していくのが正しい選択だと思う。でも少なくとも-Wallくらいは付けようね。

追記

なんか↑のエントリーにトラックバックが合計4回も送られてしまった。もしかしてはてダって更新する度にトラックバック送信されちゃうの?

*1:例:unistd.hがないとかstdint.hがないとか言われて