虚苦心観察ブログ

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

Crashlyticsでたまに発生する謎のNoSuchMethodError

エラー文はこちら。特にプログラムはCrashlyticsに関するコードを変更していません。というかできません。

01-26 16:48:42.323    7239-7239/com.zeeyousee.app.camera E/Fabric﹕ Failed to execute task.
    java.util.concurrent.TimeoutException
            at java.util.concurrent.FutureTask.get(FutureTask.java:176)
            at com.crashlytics.android.CrashlyticsUncaughtExceptionHandler.executeSyncLoggingException(CrashlyticsUncaughtExceptionHandler.java:622)
            at com.crashlytics.android.CrashlyticsUncaughtExceptionHandler.uncaughtException(CrashlyticsUncaughtExceptionHandler.java:319)
            at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
            at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)
            at dalvik.system.NativeStart.main(Native Method)
01-26 16:48:42.363    7239-7239/com.zeeyousee.app.camera E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.zeeyousee.app.camera, PID: 7239
    java.lang.NoSuchMethodError: io.fabric.sdk.android.services.concurrency.PriorityCallable.addDependency
            at com.crashlytics.android.Crashlytics.finishInitSynchronously(Crashlytics.java:739)
            at com.crashlytics.android.Crashlytics.onPreExecute(Crashlytics.java:334)
            at com.crashlytics.android.Crashlytics.onPreExecute(Crashlytics.java:223)
            at io.fabric.sdk.android.InitializationTask.onPreExecute(InitializationTask.java:27)
            at io.fabric.sdk.android.services.concurrency.AsyncTask.executeOnExecutor(AsyncTask.java:594)
            at io.fabric.sdk.android.services.concurrency.PriorityAsyncTask.executeOnExecutor(PriorityAsyncTask.java:26)
            at io.fabric.sdk.android.Kit.initialize(Kit.java:49)
            at io.fabric.sdk.android.Fabric.initializeKits(Fabric.java:417)
            at io.fabric.sdk.android.Fabric.init(Fabric.java:364)
            at io.fabric.sdk.android.Fabric.setFabric(Fabric.java:321)
            at io.fabric.sdk.android.Fabric.with(Fabric.java:292)
            at com.zeeyousee.app.account.fragment.TwitterLoginFragment.initialize(TwitterLoginFragment.java:191)
            at com.zeeyousee.app.camera.activity.MainActivity.initializeCrashReport(MainActivity.java:185)
            at com.zeeyousee.app.camera.activity.MainActivity.onCreate(MainActivity.java:58)
            at android.app.Activity.performCreate(Activity.java:5248)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2162)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2257)
            at android.app.ActivityThread.access$800(ActivityThread.java:139)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5086)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
            at dalvik.system.NativeStart.main(Native Method)

原因はCrashlyticsのプログラムアップデート?なんですかね。よくわかってないです。
プログラム側では修正できなくて開発中のアプリを端末からアンインストールしたら動きました。

2015/02/27 アプリ側の問題ではなくCrashlytics側の問題のようです。サービスに不具合があるようででそれでアプリも落ちてしまっていたようです。Fabricの初期化時にRuntimeExceptionをCatchすることでアプリの突然死を回避できます。ただこうするとアプリのクラッシュレポートが一時的でも使えなくなってしまうので、私はCatchした中で別のクラッシュレポートサービスを設定するようにしています。

OpenCVをEclipse、AndroidStudioで使うときの設定

はじめに

OpenCVは画像処理をするためのC/C++ライブラリ。
現在最新版は3.0となっているが、Android版は出ていません。
理由はしらないのですが、おそらく純C++で書かれている(2系はCで書かれていてそれをC++で使えるようにしていた)ため、Androidでそのまま使えないことが理由と思われる。

したがってここでは2系の最新版2.4.9を使うものとする。

OpenCVは適宜ダウンロードしましょう。
またOpenCV Managerを使わない方法を説明します。

Eclipseでの設定

AndroidOpenCVの準備

ダウンロードしたAndroidOpenCVを解凍し、OpenCV-2.4.9-android-sdk\sdk\java をインポートします。

これを別プロジェクトのライブラリとして設定します。

また、OpenCVの本体は.soファイルで.jarファイルと異なりライブラリとして設定しただけでは動きません。
ここまでの設定でアプリを起動し、OpenCVメソッドを実行するとUnsatisfiedLinkedErrorという例外が発生してしまうので注意。

.soファイルの配置

ndkを使わない方法

ここでは単体アプリとして動作することを目標とするので、.soファイルをアプリのプロジェクトのlibsディレクトリにコピーします。
OpenCV-2.4.9-android-sdk\sdk\native\libs 以下にあるディレクトリごとアプリのプロジェクト直下にあるlibsプロジェクトにコピー。

ndkを使う方法

.soファイルの配置方法はもうひとつあり、ndk-buildを使用する。
この方法では、プロジェクト直下にjniディレクトリを作成し、その下にAndroid.mkを作成する。
中身は以下。
```
include $(CLEAR_VARS)

# OpenCV
OPENCV_CAMERA_MODULES:=off
OPENCV_INSTALL_MODULES:=on
include C:\\\\OpenCV-2.4.9-android-sdk\\sdk\\native\\jni\\OpenCV.mk
```
作成後、jniディレクトリを作成したプロジェクトの直下でndk-buildを実行するとlibs以下にアーキテクチャごとの.soファイルが配置される。

プログラム側での設定

ライブラリとして設定するとプロジェクト内でOpenCVのクラスが利用できるようになっています。
ActivityやApplicationクラスのonCreateメソッド内でinitDebugメソッドを使うことでlibs以下に配置した.soファイルをロードします。

これでEclipseの設定は完了。

Android Studioでの設定

AndroidOpenCVの準備(主にGradleの設定)

ImportモジュールでOpenCV-2.4.9-android-sdk\sdk\java をインポートする。Eclipseのプロジェクトだがこれをモジュールとしてインポートすることができる。
モジュールとしてインポートした場合、直下のディレクトリにbuild.gradleファイルが出来上がり、トップディレクトリのsetting.gradleにモジュールが追加されているはずである。モジュールのディレクトリアイコンがただのディレクトリと違うものになっていればOK。
そうでなければsetting.gradleにモジュールを追加する。
アプリのモジュール名がapp、モジュール名がopencv-javaなら以下のようになる。
```
include ':app', ':java'
```
またアプリのbuild.gradleにはopencv-javaモジュールと関連付けるために以下の設定を追記します。
```
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:21.0.2'
compile project(':opencv-java') ## <<この行を追記する。ほかはそのまま
}
```

gradleファイルを変更したらsync project with gradle filesを実行することを忘れないように。

.soファイルの配置

Android StudioではNDKによるビルドはまだ敷居が高いです。
なのでここでは.soファイルの配置方法だけ説明します。
.soファイルの配置場所はappモジュール、opencv-javaモジュールのどちらでも良いのですが、<モジュールトップディレクトリ>/src/main/jniLibs以下に配置します。
配置方法はエクリプスと同じで、jniLibs/<アーキテクチャ名>/<.soファイル群>となっていれば良いです。

プログラム側での設定

残りはプログラムを書き、ActivityやApplicationクラスのonCreateでOpenCVLoader.initDebug()を実行すれば完了です。

Androidで画像をデコードするときの注意点

Androidでは画像の読み込み方法に大きく分けて二つの方法がある。

  1. SDカードなどパスを指定しての画像読み込み
  2. リソースフォルダdrawableに入っている画像のIDを指定して画像を読み込み

前者は基本的に副作用のないごく普通の画像デコード。
しかし後者は知らないと躓く場合があるのでまとめておく。

decodeResourceは画像のサイズ変更が行われる

BitmapFactoryのdecodeResouceメソッドは読み込んだ画像をViewで表示することを目的に作られているらしく、読み込んだ画像はAndroid端末の解像度に合わせて自動的にサイズ変更されたうえでBitmapインスタンスとして渡される。
単に画面上に表示するだけであれば問題ないが、画像処理をするために読み込んだ場合はこれが問題となることがあるので注意が必要。

Android2系ではdecodeResourceでBitmap.Configを指定しても無視される

Android4系では無視されることがないので2系に対応しているアプリを開発している場合は注意が必要である。

解像度は元画像のサイズ、Bitmap.Configを指定して読み込みたい(Android2系)、といった場合はdecodeStreamを使う。
decodeStreamの引数にはInputStreamが必要となる。
リソースファイルをInputStreamとして取得するにはResourcesのopenRawStreamメソッドを利用する。
以下は実装例。

InputStream istr = context.getResources().openRawStream(R.drawable.image);
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inPreferedConfig = Bitmap.Config.ARGB_8888;
Bitmap image = BitmapFactory.decodeStream(istr, null, opts);

2画面スマホ Medias W レビュー

購入の動機-Galaxy Note捨てたい

本当はもう少し待ってから買おうと思ってたのですが、Galaxy Noteが使えない子なので我慢しきれず半月ほど前に購入しました。

Galaxy Noteからの乗り換え候補としてはXperia ZとかOptimus Gとかあったのですが、ガジェット好きの自分にはどうしても変態2画面のMedias W が気になって仕方がなかったのです。
正直、「この変態さ加減はいかがなものか」と思っていたのですが、店頭で試しに数回使ってみると案外癖がなく良い感じなことが分かってからというもの、いつ買おうか悩みに悩んでいた次第なのです。

外見-裏表上下がわかりにくい対称デザイン

実物を見たことのない人が「2画面スマホ」という言葉から連想するのはSonyが以前販売していたSony Tablet P のように画面を内側に折りたたむデザインでしょう。だって画面が傷つきませんしね。

しかし、Medias Wは内側ではなく外側になるように折りたたむデザインになっています。
これはかなり変態。画面傷つくじゃん。手脂でベタベタじゃん。

でも、このデザイン、普段使いを考えると結構理にかなってるんです。

折りたたんだ状態でも画面が外に出ているので、開くことなくスマホをいじれます。

また、閉じた状態だと画面の片方は自動で電源が切れて、もう片方だけが表示されます。これが結構良い感じで、画面が半分になることで電池の消費が抑えられるのです。


このデザインで一番気になるのは、画面が傷つくこと、です。

さすがにメーカーもその辺は認識しているらしく、ちょっとした工夫がされています。
画面の上下にある濃いグレーの部分が画面より少しだけ厚くなっているようで、スマホを机などに置いたとしても画面が直に机に触れないようになっています。

ただ単に変態なだけでなく、欠点を補うための工夫がされているのはいいですね。

また、それだけだと安心できないからか画面保護シートも最初から付属しています。
こういう配慮もいいですね。

中身(UI)-見た目に反してに近い

Galaxy系は見た目こそ普通ですが、中身はゴテゴテにカスタマイズされていてなんかヤナ感じだったのですが、Medias W は見た目は変態ですが、中身は結構素に近いものでした。個人的には好印象です。

さすがに2画面のための特殊な設定項目は存在するものの、それ以外は素な感じ。

2画面モード

2画面モードには画面を完全に開くことで自動的に変更されます。
このとき、2つ目の画面をどう使うかで2つの状態が選べます。

2つの画面を1つの画面として扱う「フルスクリーンモード」
それぞれの画面で別々のアプリを起動する「ダブルモード」

これらの詳しい情報はニュースサイトのレビューが説明していると思うので省略。

1画面モード2画面モード行ったり来たり

面白いことに1画面モードから2画面モードへの移行、またはその逆、は思いのほか正常に動作しています。
たいていのアプリではエラーが発生せずに動いてくれます(ゲームとかはさすがに無理)。
普段使っているアプリでダメだったのは、Kindle
1画面モードから2画面モードにするとクラッシュしてしまいました。

また、画面を開くとアプリによっては勝手に画面を回転するものもあります。
おそらくアプリ内で画面の縦横判定をしているものと思われます。
Medias Wは画面を開くと、縦よりも横のほうが長くなるので、このようなことが起こっているようです。
そのほうが何かと都合が良いので私は気にしてません。

総評-後悔なんてない。むしろなぜもっと早く買わなかった。

このスマホ、結構名機だと思います。
作りは特殊で使う人を選びそうな作りをしてそうですが、中身は堅実な作りになっていてAndroidを使ったことのある人なら戸惑うことなく利用できるようになっている点はすごく良い。

2画面モード時の機能もたのしいし、実用的。
フルスクリーンモードなら本を読むときに便利だし、ダブルモードならGoogleマップを表示しながらWebで検索もできる。
2つの画面をフル活用できる点はすごく嬉しい。

そういえば電池の持ちやレスポンスについて何も書いていませんでした。
書き忘れてしまうほどに問題ないのです。
つまり他のスマホと全く差がない。
もしかしたら同じスペックのスマホよりレスポンスは良いかも、と思ってしまうほど。


閉じた状態なら普通のスマホ。
開いたときだけこいつだけが持つ力を発揮してくれます。

ゆえに変態であることを意識せずに使えていいのだと思います。

AndroidHT-03A から使っていますが、それとMedias Wは忘れられないスマホになりそうな気がしています。

pebble Kickstarter Edition

届いてからもう3週間ほどたってしまっているのですが、pebbl についてレビューしようかと。

pebbleの箱。この状態で運ばれてきました。
f:id:ysuzuki116:20130416203853j:plain

腕につけてみたところ。
バックライトなしでも視認性は高いです。
f:id:ysuzuki116:20130416210140j:plain

そもそもpebbleって?

pebble とは最近騒がれているスマートウォッチに類するガジェットです。
スマートウォッチはAppleが作っているらしい、Googleがー、Microsoftがーと話題になっていました。

そんなスマートウォッチの先駆け的な存在です。

何ができるの?

スマートウォッチというくらいですから基本的に時計です。
当たり前だけど基本って大事。Sony から MN2 っていうスマートウォッチが出ていたのですが、今考えるとあちらは時計という機能がだいぶ蔑ろにされていて使いづらかったです。

それから盤面がカスタマイズできます。
今は有志によって開発されていて様々な盤面を手に入れることができます。
以下がそのサイト。pebble と接続したスマートフォンからアクセスすることで盤面がインストール出来ます。
Pebble Watchapp Directory - Pebble Forums

私のお気に入りはどーもくんの盤面。時間が変わるごとに口をパクパクするのが良い感じ。
Watch Face: Noms - Pebble Forums

他にできることはと言うと、メールの受信と電話の着信通知。
さらに簡単なアプリケーションをインストールできるので、いろんなことができます。

pebble VS MN2

他のスマートウォッチとの比較ということで私が持っているMN2と比較してみようと思います。

時計としての役割

pebble >>> MN2

これはpebbleの圧勝です。

MN2 は単体で動くことができず、常にスマートフォンと接続している必要があります。接続が断たれると時計の表示はなんとかできますが、一度電源を切ると時計すら表示出来ません。
さらに言えば、画面が普通の液晶のため点きっぱなしだと電池を消耗してしまうため、画面はすぐに消えてしまい、時間を確認するために、電源ボタンを押すか、振らなければなりません。

それに比べpebbleは初回起動時にスマートフォンと接続すれば、接続を断とうが電源を切ろうがちゃんと時計を表示してくれます。
盤面は電子ペーパーを利用しているため、常に表示されているという点も良いです。

視認性

pebble > MN2

pebble の盤面は常に表示されていて、見る角度によって見えないということもありません。
MN2 の画面は基本的に消えており、自分で付けないといけません。視認性とは違うかもしれませんが、この点はマイナス。つければその視認性は液晶と同じなので問題有りません。

カスタマイズ(盤面編)

pebble >> MN2

これはMN2には無い機能なので比較になりません。
MN2はサードパーティによる盤面のカスタマイズはサポートしていないからです。

カスタマイズ(アプリ編)

MN2 > pebble

これに関してはMN2が勝ります。
なぜかというと、MN2は時計と言うよりはスマートフォン第二画面として機能するため、スマートフォンが許す限りの機能を提供できるからです。
ただし、やはりスマートフォンとセットが絶対な点がマイナス。それ故に強力であることは確かですが、単体で使えないのはどうかと。

pebble は MN2 とことなり時計自体にアプリをインストールすることが可能です。
そのため、機能はだいぶ劣りますし、インストールできるアプリの数もかなり少ないです。
が、pebble 単体でアプリを動かすことができる点は個人的には高評価。

操作性

pebble > MN2

僅差でpebbleかな。
正直、人によって好みがわかれるかと。

pebble には、決定、戻る、選択ボタン1・2の4つのボタンがついており、それですべての操作を行うことができます。
ボタンなので操作がわかりやすい点が良いですね。ただボタンが硬い。

対してMN2は近代的なタッチパネル。アプリによってはタッチパネルを生かしたものも。しかし、画面が小さいことが災いして操作性が良くないのが難点。

バッテリーの持続時間

pebble == MN2

これに関してはほぼ互角。
両方共激しく使わなければ1週間は持ちます。

防水性能

pebble >> MN2

pebble は5気圧防水なのに対して MN2 は防滴対応なので比べようがありません。
ただ pebble も5気圧防水なので水に潜ったりとかはダメで、シャワーとか洗い物で水がかかるのが大丈夫な程度。つまり日常生活で水がかかるくらいなら問題ありません。

ベルトの交換

MN2 > pebble

MN2の勝ちでしょうか。
MN2は時計と言いながら、本体はクリップ形式なのでいろんなところに付けることができます。さらに時計用のシリコンベルト、市販のベルトを取り付けられる台座が標準で付いてる点も良い点。

pebble は本体にベルトが付いているため交換できないみたいなのでこれに関してはどうしようもない。
と、思いきや交換されているかたがフォーラムにいました。どこで見たかは忘れましたが。もしかしたら市販のベルトと交換できるのかもしれません。

総評

pebble >> MN2

私的には pebble の圧勝です。
pebble が一番評価できる点は、単体で機能する点。それ故に使い勝手が良く、それなのに電池も持つ、基本である時計としての役割を果たしている。MN2に勝てるわけがないのです。

おわりに

pebble いかがだったでしょうか?
pebble はスマートな機能と時計としての機能のバランスが絶妙だと、私は思っています。
腕につけて使う以上、人間が操作できることに限りがあるのでスマートフォンからの通知と遊び心。この2つが大事なんじゃないかなと。

今のところ Kickstarter で投資した人しか手に入れることができないガジェットなので、この記事を見てすぐ買うことはできませんが、将来発売された時の参考にしていただけたら幸いです。

今回はMN2をかなりけなしていますが、アレはあれで割り切った設計になっているおかげで遊べるものになっているので悪いものではありません。
しかし、あれは時計ではありません第二画面なのです。
その点だけ評価すればいいものなのですけどね。

Kindle paperwhite 自炊実験-小説の圧縮形式と品質の評価

最近Kindle paperwhite を買いました。結構今更感が強いのですが。
しかし、これには理由があります。
まだ日本でKindleが発売される1年以上前、今で言うKindle keyboardを購入していたのです。
なので購入しない予定だったのですが、年末のAmazonでのCyber Mondayでスキャナを購入し、その後裁断機を購入してから自炊した本をAmazon経由でKindleで受け取ろうと思ったのですが、いろいろ問題&面倒だと思って購入した次第です。

問題&面倒というのは以前購入していたKindle keyboardが米Amazonから日Amazonに移行することが出来ず、Androidで利用している日Amazonのアカウントと同期が取れず、そのままだと米と日のAmazonを併用しなければならなかったのです。
個人的にはひとつの米と日のどちらかで統一したかったのですが、ハードウェアの制約でそれは無理でした。やろうと思えばそのまま2つのアカウントを併用することもできるのですが、さすがに面倒なので「ま、ライトもついて小さくなるしいっか」と思って結果的に購入に至りました。



基本的には自炊以外で使う予定はないので、スキャンした画像をKindleで表示する上で圧縮率がどのように容量とその表示に影響するのか調べてみようと思い、以下の実験を行いました。

  1. JPEG圧縮による文字列への影響はどんな感じになる?
  2. 実際にKindle paperwhiteで表示したらどうなる?
JPEG圧縮による文字列への影響はどんな感じになる?

だいたいKindle whitepaper の解像度に合わせて異なる品質でJPEGで圧縮した後、一部を切り抜いた画像です。
ここでは文字列のスキャン結果を利用してその比較をしてみます。
利用した画像処理ソフトはフリーでお馴染みのGIMP
品質は 1~20の間で設定して実験しています。

品質 1
f:id:ysuzuki116:20130331223832p:plain
品質 3
f:id:ysuzuki116:20130331223837p:plain
品質 5
f:id:ysuzuki116:20130331223841p:plain
品質 10
f:id:ysuzuki116:20130331223846p:plain
品質 15
f:id:ysuzuki116:20130331223849p:plain
品質 20
f:id:ysuzuki116:20130331223853p:plain

上の画像を見る限りだと1~10でJPEG特有のもやもやが目立ちますね。
そりゃそうですよね。1~10はかなりの圧縮率になりますから、もとの画像に無駄なものが入ったり、抜けたりしてしまいます。

実際にKindle paperwhiteで表示したらどうなる?

Kindleにも入れて実際のところを確認してみましょう。
Kindleに入れるにあたっては、ChainLP というフリーソフトを利用しています。
No.722: ChainLP
上記のURLで公開されています。
高機能で使いやすくもあり、これだけのものをフリーで公開してくださっている作者さんには感謝です。

気づいている方もいると思いますが、使っているソフトが違うので上の結果がそのまま反映されていません。(出来れば、ChainLP→画像抜き出しでやりたかったんですけど、やり方が分からなくて・・・というか面倒で・・・とりあえずということで。)

では、以下が比較です。
JPEGに加えてPNGでも圧縮しています。画像はKindleで表示したものをデジカメで撮影したものを一部編集したものです。
また、カッコ内の値は1冊450ページの小説を各設定でmobi形式で電子書籍化した時の容量です。

JPEG 品質 1(17.5MB)
f:id:ysuzuki116:20130401222513p:plain

JPEG 品質 3(17.5MB)
f:id:ysuzuki116:20130401222543p:plain

JPEG 品質 5(22.9MB)
f:id:ysuzuki116:20130401222618p:plain

JPEG 品質 10(32.6MB)
f:id:ysuzuki116:20130401222633p:plain

JPEG 品質 15(40.2MB)
f:id:ysuzuki116:20130401222649p:plain

JPEG 品質 20(46.6MB)
f:id:ysuzuki116:20130401222705p:plain

PNG 色深度 1bit(22.6MB)
f:id:ysuzuki116:20130401222728p:plain

PNG 色深度 2bit(38.2MB)
f:id:ysuzuki116:20130401222746p:plain

PNG 色深度 3bit(55.5MB)
f:id:ysuzuki116:20130401222806p:plain

PNG 色深度 4bit(67.7MB)
f:id:ysuzuki116:20130401222826p:plain

色深度は8bit(0-255)まであるのですがKindleが16階調しか表現出来ないので4bitまでしか作成していません。


試して見た限りだと文字列についてはPNGの1bitが、見やすさと圧縮率の一番バランスが良かったように思います。

同じ圧縮率であるJPEG 品質 5では若干見にくいところがありますし、同じくらいの見やすさとなると容量が大きくなってしまいます。

小説のような文字中心のものを表示するだけならグレースケールではなく、モノクロで十分ということでしょう。

今回は以上になります。
暇があればマンガでもためしてみたいですね。

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について知らなくても利用することが出来ます(もちろん知っていることに越したことはないです)。
さらに記述する量も少なくて済むので経済的です。

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