虚苦心観察ブログ

ブログ管理者である虚苦心が私利私欲に基づいて書いているブログです。主にガジェットのレビューだったり、画像処理のことだったりを記事にしています。

CMake + Cutter で簡単にテスト&ビルド。

仕事でプログラムを書いているわけですが、Makefileはベタ書き、テストはまともに書いていませんでした。

で、最近から書き始めたコードではさすがにそれはまずいだろう、今後の自分のためにならないだろうと思い、CMakeやCutterについて勉強しはじめました。

CMakeというのはMakefileVisualStudioのソリューションを作ってくれるソフトウェア。役割としてはautotoolsとほぼ同じ。ただ根本的に違うこと一つあり、autotoolsは主にUnix系OS向けなのに対し、CMakeはクロスプラットフォームUnix、Windowsなどは問わないのです。

有名なところだと画像処理ライブラリであるOpenCVで利用されています。OpenCVはCMakeの売りであるクロスプラットフォーム対応を最大限活用してUnix、Windows、さらにはiOS、Androidにも対応させています。

ただ、ここではそんな高度なことは全くするつもりなんてありませんし、そもそもできません・・・

ここではクロスプラットフォームなんて単語は無視してMakefileを簡単に生成するためだけに利用します。

次にCutter。これはテスティングフレームワークで同種のもので有名なところだとCUnit、CppUnitなどでしょうか。

Cutterの特色は簡単に書けること。テストプログラムでよくあるよくわからない呪文は無く、よくわからない手順もかなり簡略化されています。

さて、CMakeやCutterをなぜ使おうと思ったかというと、よく使われているツールより簡単そうだったから。ただそれだけ。

(だって今からMakefileの書き方とかautotoolsの使い方、CUnitのよくわからない呪文なんて覚えたくないし、楽できるならソッチのほうがいいじゃないですかー。楽できて同じ事ができるならそれでいいじゃないですかー。)

というわけで自分が忘れないためにもCMakeとCutterの使い方についてまとめていこうかと思います。

ブログを書く手間を省くため、ここではCMakeの書き方とビルド、Cutterの実行だけ説明しようと思います。
Cutterの書き方についてはまた後日、気が向けば。

ではCMakeの書き方について。
参考にさせていただいたのは以下の二つのサイト。
よくわからない現代魔法 cmakeの使い方メモ
CMakeを使って自作ライブラリをビルド&インストールしてみたまとめ - へぼいいいわけ
利用したプログラムのソースはCutterのチュートリアルから拝借。
cutterのソースプログラムのsample/stack以下のファイルを利用し、autotools用のファイルを無くしてCMakeのファイルに置き換えています。

CMakeを使うにはCMakeLists.txtというファイルを作ります。
ディレクトリ・ファイル構成は以下とします。

cmake_cutter
   |-- CMakeLists.txt
   |-- src
   |   |-- CMakeLists.txt
   |   |-- stack.c
   |   `-- stack.h
   `-- test
       |-- CMakeLists.txt
       `-- test-stack.c

トップディレクトリであるcmake_cutterにあるCMakeLists.txtは以下のように書きます。

# これはコメント
cmake_minimum_required(VERSION 2.6) # このCMakeLists.txtを実行するのに必要なバージョンの下限

subdirs("${PROJECT_SOURCE_DIR}/src" "${PROJECT_SOURCE_DIR}/test") # 指定したディレクトリ以下のCMakeLists.txtを実行する。
# ちなみに PROJECT_SOURCE_DIR はCMake側で定義済みの変数。ここではcmake_cutterになる。

中身は最低限の記述だけ。
重要なのは実行に必要なバージョンの下限と、サブディレクトリの指定。説明はプログラムを参照。

次にsrc以下にあるCMakeLists.txt。

add_library(stack SHARED stack.c) # ビルドするライブラリの設定。
# 第一引数はライブラリ名、第二引数はビルドするライブラリのタイプ。第三引数はライブラリに含めるプログラムのソースファイル名。

これだけ。やっているのはライブラリのビルド設定のみ。

最後にtest以下のCMakeLists.txt。

include_directories(${PROJECT_SOURCE_DIR}/src /usr/include/cutter) # インクルードファイルのあるディレクトリ。
# stackプログラムのあるsrcとcutterのインクルードディレクトリがある/usr/include/cutterを指定している。

link_directories(${PROJECT_BINARY_DIR}/src) # リンクに必要なファイルのあるディレクトリの設定。
# PROJECT_BINARY_DIR はビルド時に利用するディレクトリ。あとで作成するbuildディレクトリがそれになる。

add_library(test_stack SHARED test-stack.c) # ライブラリのビルド設定。
# cutterはテストの実行にシェアードライブラリを利用する。

target_link_libraries(test_stack stack) # リンク設定
# test-stack.c で利用しているstackプログラムをリンクするように設定している。
# リンクする対象であるtest_stackが定義されてからtarget_link_librariesを実行する必要があるので、add_libraryの後に書かれている。前に書くとエラーになる。

こちらでは少し細かな設定をしている。
srcディレクトリではコンパイルのみで標準のライブラリ以外使っていなかったので、add_libraryによるライブラリのビルド設定だけでしたが、testではビルドされたstackライブラリのインクルードとリンクの設定、cutterライブラリのインクルードの設定が必要です。なのでinclude_directoriesとlink_directoriesを使ってディレクトリを指定しています。
また、リンクについてはリンクするライブラリも指定する必要があるので、target_link_librariesでライブラリを指定しています。

これでCMakeの設定は完了。
Cutterのチュートリアルを読むと分かるのですが、autotoolsの設定は異様に長くて意味不明、Makefileの記法まで覚えなければならないので大変です。
それに比べてCMakeは上記のようにCMakeLists.txtを書くだけなのですごく簡単です。

それではCMakeを実行しましょう。
CMakeを実行するにはcmake_cutterへのパスを指定する必要があります。

$ cmake <cmake_cutterへのパス>

これはソースファイル群を含んだディレクトリとビルドファイルを分離できるようにして、メンテナンスなどをしやすくしているものと思われます。
なので、ビルドに利用するディレクトリを作成してCMakeします。

cmake_cutter
   |-- CMakeLists.txt
   |-- build #<=これを作成
   |-- src
   |   |-- CMakeLists.txt
   |   |-- stack.c
   |   `-- stack.h
   `-- test
       |-- CMakeLists.txt
       `-- test-stack.c

buildディレクトリ下に移動し、以下を実行します。

$ cmake .. #親ディレクトリなので相対パスで指定
-- The C compiler identification is GNU
-- The CXX compiler identification is GNU
-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/kyokushin/programing/cmake_cutter/build

これでMakefileが作成されました。
あとはmakeコマンドを実行するだけ。

$ make
Scanning dependencies of target stack
[ 50%] Building C object src/CMakeFiles/stack.dir/stack.c.o
Linking C shared library libstack.so
[ 50%] Built target stack
Scanning dependencies of target test_stack
[100%] Building C object test/CMakeFiles/test_stack.dir/test-stack.c.o
Linking C shared library libtest_stack.so
[100%] Built target test_stack

これでビルド完了。
build/src以下にlibstack.so、build/lib如何にlibtest_stack.soが作成されているはずです。

あとはテストを実行するだけ。
Cutterではテストの実行にcutterコマンドを利用します。
cutterコマンドの引数にはテスト用プログラムのシェアードライブラリが含まれたディレクトリを指定します。
ここではbuild/testになります。

$ cutter test/                                                       
...

Finished in 0.006037 seconds (total: 0.001482 seconds)

3 test(s), 15 assertion(s), 0 failure(s), 0 error(s), 0 pending(s), 0 omission(s), 0 notification(s)
100% passed

Cutterのソースファイルに含まれているstackプログラムは完成済みなのですべてのテストに通過するはずです。

これでCMakeの書き方からビルド、Cutterの実行までが終わりました。


ここで言いたいことは、

CMakeってAutotoolsより簡単でしょ?

ってこと。


Autotoolsを使おうとするとまずはMakefileの記法について熟知している必要がありますし、さらにAutotoolsの動作についても知る必要があります。
しかし、CMakeではMakefileを作ってくれるのでMakefileについて知らなくても利用することが出来ます(もちろん知っていることに越したことはないです)。
さらに記述する量も少なくて済むので経済的です。

ただ問題は情報が少ないこと。英語の情報は比較的あるのですが、日本語の情報はまだまだで本格的に使っているところも無いみたいなので、細かな使い方が未だに分かっていない状況です。