百日半狂乱

Shut the fuck up and write some code!!

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

場当たり的な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

続きを読む

googletestを/usr/local/にインストールするシェルスクリプト

発声練習:Intel C/C++ を用いた Google Test環境を準備するを参考にしてgoogletestのセットアップを行うシェルスクリプトを書いた.

ホームディレクトリにソースを落としてきて、コンパイルした後に/usr/local/に必要なヘッダとライブラリをcpしているだけ.

cmakeが必要なので、なければ予めパッケージを落としてくる.

gtestを/usr/local以下にインストール/アンインストールするシェルスクリプト

googletest自体については、googletest入門ガイドが翻訳されている.

こいつを使ってTDDを実践したいんだけど、ビルドプロセスやテストの自動化で永久にyak shavingやってる、二年くらい.

2014/2/6追記:googletestに関して調べたことメモ

fused source files

エンジニアのソフトウェア的愛情:googletest1.5.0の使い方・その1:ビルドする

どうも、1.5.0からテストをビルドする度にgoogletestも再コンパイルせよという方針らしい.

エンジニアのソフトウェア的愛情:Google Testをインストール、しないですませる方法

それで、毎回再コンパイルするってどうすんのって話になる.

どれを使うの?って話は1.5.0から追加された「fused source files」で解決する.

リンク先にある通り、二つのソースと一つのヘッダをプロジェクトに絡めるだけで、テスト環境が手に入る.

手元の環境が仮想環境だった場合、コンパイルに時間がかかるのが辛い.

問題ないなら、/usr/local/にセットしたらライブラリのリンクですませたい.

googletest付属のサンプル

どうやって毎回再コンパイルするの?って話は同伴されているサンプルテストをビルドするMakefileを見ればわかる.

このMakefileの読み方とgoogletestについて素晴らしい解説を行っているエントリを見つけたのでメモ.

minus9dの日記:googletestを使いこなす

minus9dの日記:googletestに付属するサンプルを読み解く

リンク先ある解説図を見れば、/usr/local/以下にセットしたライブラリに何が含まれているかが一目瞭然.わかりやすいなぁ.

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

nmコマンドでC/C++のシンボルテーブルを見る、C++の名前マングリング、"C"リンケージ、あるいはリンカに関するメモ

前回(g++)前々回(gcc)のサンプルコードを使ったC++のマングリングや"C"リンケージに関するメモ.

nmコマンドでサンプルコードのシンボルテーブルを覗いた後に、C++からCの関数を呼び出す場合のサンプルコードを示す.

特にリンケージ周りの説明は正確性を欠いているやもしれませんのでご容赦下さい.より詳細な説明は参考リンク等を参照して頂ければと思います.

nmコマンド

nm は、UNIXや類似のオペレーティングシステムに存在するコマンドであり、バイナリファイル(ライブラリ、実行ファイル、オブジェクトファイル)の中身を調べ、そこに格納されているシンボルテーブルなどの情報を表示する。デバッグに使われることが多く、識別子の名前の衝突問題やC++の名前修飾の問題を解決する際に補助として用いられる。

GNUプロジェクトでは、高機能の nm プログラムを GNU Binutils パッケージの一部として提供している。この nm コマンドは他のツールと同様に特定のコンピュータ・アーキテクチャとバイナリフォーマット向けにコンパイルされているので、セキュリティ専門家は疑わしいバイナリファイルを調査するためにネイティブでない nm コマンドを事前に取り揃えておくことが多い。

Wikipedia - nm(UNIX)

今回はこいつを使って、サンプルコードのコードのシンボルテーブルを見たり、C++からCの関数を呼び出す場合に起こる問題等について見ていく.

続きを読む

C/C++の関数プロトタイプ、暗黙ルールデータベースの話(その2)

前回の記事で公開したMakefileでは、gccコンパイルオプションに-Wallを付けていなかった.

極めて非人道的である.

現在Makefileを修正してコンパイル時に-Wallを付けるようにしたが、そのままmakeを叩くとコンパイラにしっかり警告を食らった.

run.c: In function ‘main’:
run.c:4:2: warning: implicit declaration of function ‘print_hello’ [-Wimplicit-function-declaration]

これは、前回のコードではmain関数でprint_hello()を呼び出しているが、それに先立って行うべき関数のプロトタイプ宣言を行っていないからである.

しかし、gccでは警告を食らうだけで、コンパイルは通ってしまう.

関数プロトタイプ(Function prototype)

Cで、もといgccで、関数プロトタイプがなくてもコンパイルが通るのは以下の理由による.

関数が事前に宣言されていない状況で、左括弧付きで式の中に現われた場合、その関数は暗黙のうちに int を返すものと判断され、引数については何の想定もなされない。

Wikipedia - 関数プロトタイプ

Wikipediaにも書いてある通り、書かない場合に問題が発生するので、基本的に関数プロトタイプを省略してはならない.

C++ではコンパイルが通らない

C++では、もといg++では、そもそもコンパイルが通らない.

前回のMakefile中の変数CCをg++にしてmakeを叩くと警告が出るだけでコンパイルが通ってしまうgccとは違って、コンパイラがエラーを吐く.

run.c: In function 'int main(int, char**)':
run.c:4:14: error: 'print_hello' was not declared in this scope
make: *** [run] Error 1

どうもg++では、関数プロトタイプが必須らしい.

g++でコンパイルが通るようにする

以下は、前回のコードをC++(g++)に合わせて若干変更したもの.

makeでライブラリ(.a)のビルドを管理するサンプル(g++.ver)

前回と違って.cファイルを.ccファイルとした上で、hello.hに関数プロトタイプを追加し、run.ccでhello.hを#includeするようにしている.

暗黙ルールデータベースの活用

上記のC++バージョンのコードは、Makefile前回のCのMakefileと少し違う.

ここではそれぞれのMakefileの記述が暗黙ルールデータベースにどのように作用しているかを比較してみることで、もう少し暗黙ルールデータベースに対する理解を深める.

続きを読む