読者です 読者をやめる 読者になる 読者になる

百日半狂乱

Shut the fuck up and write some code!!

非再帰的makeでgoogletestのテストコードを含むソースツリーを管理するMakefileを書いた

googletest Makefile TDD test make C/C++ Linux

場当たり的なMakefileで管理しているC/C++のコードの規模(数千行程度)がそれなりに大きくなってきた.

テストがないので大きな変更がしんどい.

テストがないのでバグを踏んでも何が原因かは勘とprintfデバッグ、辛い.

もういろんなところでテストがまったくないなんてありえないと言われている.

テストがないコードは全てレガシーコード.

どうせならTDD実践したい.

Linux上で、エディタはvimで、コードはGitで管理して...

C/C++だからテスティングフレームワークはgoogletestにしよう.

規模がある程度大きくなるので、分割コンパイル.

TDDなので、テストを書いたらすぐ実行したい.

なるべく早くフィードバックが欲しいので、変更を加えたソースファイルに関連するコンパイルのみが走って、なるべく早くテストを実行したい.

条件に当てはまる開発環境は?みんなはどうしているの?

googletestを使ってみた系の記事はサンプルコード以上の記述がない.

TDDBCで使ってるのはVC++かな?

OSSプロダクトはAutotoolsCMake?なんだかが深そう.

IDEの言いようのない裏で何やってるかわからない感.

ビルドプロセスは明確にしておきたい.

プレーンテキスト!!

テキストフィルタリング!!

CLI!!

黒い画面!!

etc...

と言った様々な想いとか趣味趣向などが交錯して、どうしても思い描いた開発環境が欲しくなって書いた.

Autotoolsから逃げて「巨人の肩に乗れ」という原則を思いっきり破っていて、やってて楽しい一方でモヤモヤした気持ちは今でも拭えてないけど、とにかく書いた.

もう環境を整えるのに時間かけたくないので、githubから落としてきたらすぐにでも始められるように小さなスクリプトも書いた.

Makefileと関連するシェルスクリプトgithubに上げた.

https://github.com/doi-t/nonrec-make-with-gtest

勢いでREADMEも書いた.

最初は、何もないとブログに全部書かなきゃならない、と思ってREADMEを書き始めたんだけど、強制的なドックフーディングになったりして色々気づきが多く良い経験になった気がする.

だけど、どこまで説明するか決めないまま書き始めたせいで、途中で変更が入ったり、出来上がる前からああでもない、こうでもないと修正したりして時間ばかりかかった.

もう第三者がまず欲しい情報が何かわからなくなってしまっているので、わかりにくい所とかあったら教えてもらえると本当に嬉しいです.

再帰的make(non-recursive make)

再帰的make(non-recursive make)は論文: "Recursive Make Considered Harmful"で提案された手法らしい.

具体的な非再帰的makeの実現には "GNU Make 第3版、6章 大きなプロジェクトの管理" に載っているコードの大部分を参考にした.

本書では、上記論文を引用した上で、具体的な例の解説がなされている*1

gistに同書のサンプルコードに対するメモを上げているので、わかりにくいかもしれないけれど参考までに.

GNU Make 第3版、第6章の非再帰makeのサンプルコードに対するメモ

結局、自分がやったことは、このサンプルコードが管理するソースツリーにテストコードのコンパイルと実行を絡めただけ.

実際に非再帰的makeを適用しているOSSプロダクトOpenRADIUSMakefile解説が有名.上記論文のサイトでもリンクが張られている.

このOpenRADIUSではスタックポインタを利用して、ソースツリーの階層が増えた場合にでも対応できる非再帰的makeを実現している

参考:stackoverflow上での、non-recursive makeに関する議論

ユニットテストの戦略

現時点での妄想になるけど考えている戦略をメモ.

再帰的makeを見て、こいつにテストを絡めようと思ったのは、半強制的にモジュールがライブラリ化されるからというのがあった.

例えば、githubに上げているサンプルコードは、以下のようにsampleというメインルーチンがaddという関数を呼び出しているのだが、そのadd関数はライブラリlibadd.aに含まれている.

f:id:doi-t:20140209162718j:plain

テストは特に不安の大きい機能の表層、API部分に書くと効果的だとどこかで見た.

テストの濃淡で言うところの濃い部分というのは、ちょうどライブラリが提供する機能あたりなような気がする.

もう少し複雑になって、ライブラリがライブラリの機能を利用している場合にでも、以下のようなイメージでテストを書いていけば、良いのではないかと妄想している.

f:id:doi-t:20140209162731j:plain

この絵は、足し算(add)と引き算(sub)を行うライブラリをlibfunc.aというライブラリが呼び出して、メインルーチンsampleがlibfunc.aを通じて間接的にlibadd.a、libsub.aを利用しているイメージ.

libfunc.aが提供するAPIに対するテストはもちろん、libadd.a、libsub.aに対しても不安を感じたらテストを書く.

書いたMakefileは個々のライブラリやテストを追加したり更新したりすると、対応するライブラリやテストコードのコンパイルのみが走るようになっている.

規模が大きくなっても、テストが実行されるまでに行われるコンパイルの数はそれほど変わらないので、フィードバックサイクルを短く保てるようにしているつもり.

ライブラリ自体が壮絶に巨大になったり、テストコードが巨大になるとどうなるかはわからない*2

半強制的にライブラリという単位を意識させられるので、機能を疎結合に保つ努力が自然と行えると良いなぁと思ってる.

雑記

ドキュメントを書いては修正してみたり、絵を描いてみたり、何を必死になっているのか自分でもわからないけど、なんかもう定期的に溜まったものを吐き出さないと次に進めなくなってきた感がある.

それでも相変わらず時間かけ過ぎだし、いちいち長いのでもっと書き殴りな文章に移行していきたいけど、性格的に難しいので気長にやる.

後、一人で勝手に高まってるのは、先日参加したオープンセミナー広島2014(#osh2014)の影響をモロに受けているせい.

セミナーについてはまた後日、感想等のエントリーを書きたいと思っている.

実行委員長の方が「学んだことを何かに役立てるまでが勉強会」と言っていたのだけど、自分にとってはこれもそのうちの一つ.

現状、テストの導入自体が目的化してしまっていて、肝心のgoogletestの学習やTDDの実践がまったく進んでないため、本末転倒な感じだけど、これから頑張る.

GNU Make 第3版

GNU Make 第3版

二十五日半狂乱、12日目(の分)の記事

*1:8章では、CとC++をテーマにして、ソースとバイナリの分離などさらに突っ込んだ解説が行われている

*2:その場合は、ソースファイル単位でコンパイル実行を考える必要がありそう