虚苦心観察ブログ

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

OpenCV + CMake + Visual Studio

はじめに

CMakeはUnixWindowsなど各ビルド環境に応じたビルドファイルを生成することで、各プラットフォームに依存しないビルドファイル生成プログラムです。 ライブラリで利用されていることが多いため、ライブラリを利用する側にメリットがないように思われる方も多いと思いますが、実はライブラリを使う側にとってもとてもメリットのある便利なプログラムになっています。

面倒な設定をCMakeで解決

ライブラリを自作のプログラムに組み込むときにはインクルードファイルやリンク時に必要なスタティックオブジェクト、シェアードオブジェクト、もしくはLibファイルなどそれらの設定を作成するプログラムに応じてMakefileを作成したりVisualStudioの設定を変更したりしなけらばなりません。 しかしCMakeで作成されたライブラリにはインクルードファイルやリンク時に必要なファイル群の場所が書かれたファイルが用意されており、これを読み込ませ、数行の設定を記述するだけでライブラリを使う設定が完了してしまいます。 VisualStudioを使っている方はこれらの設定が特に面倒ですが、それらがなくなりプログラム内にpragmaを書く必要もなくなるのでとても簡単にプロジェクトの作成ができるようになるのでおススメです。

簡単な利用例

というわけでCMakeを使ったライブラリとして、また画像処理ライブラリとして有名なOpenCVをプログラムに取り込む方法を紹介しようと思います。

さっそくですがCMakeの設定ファイルであるCMakeLists.txtを載せます。

CMAKE_MINIMUM_REQUIRED(VERSION 3.0)

find_package(OpenCV REQUIRED)

add_definitions(${OpenCV_DEFINITIONS})
include_directories(${OpenCV_INCLUDE_DIRS})
link_directories(${OpenCV_LIBRARY_DIRS})

add_executable(OpenCV_sample main.cpp)
target_link_libraries(OpenCV_sample ${OpenCV_LIBRARIES})

set(CompilerFlags
    CMAKE_CXX_FLAGS
    CMAKE_CXX_FLAGS_DEBUG
    CMAKE_CXX_FLAGS_RELEASE
    CMAKE_C_FLAGS
    CMAKE_C_FLAGS_DEBUG
    CMAKE_C_FLAGS_RELEASE)
foreach(CompilerFlag ${CompilerFlags})
    string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}")
endforeach()

find_package()コマンドはCMakeで作成された外部ライブラリを取り込むためのコマンドです。 これを記述することで以下の変数が生成されます。 OpenCV_DEFINITIONS OpenCV_INCLUDE_DIRS OpenCV_LIBRARY_DIRS OpenCV_LIBRARIES

またfind_packageコマンドは探すパスが決まっています。 以下は本家のドキュメント。 find_package — CMake 3.0.2 Documentation

もう一つは日本語でまとめてくださっている方。 qiita.com

結論としては環境変数CMAKE_PREFIX_PATHに探索してほしいパスを追記していくことでfind_packageコマンドが見つけてきてくれます。 追記するパスにはOpenCVConfig.cmakeが含まれている必要があります(OpenCVConfig.cmakeを含むディレクトリがあればいい場合もあります。詳しくは上記のリンクを参照)。

以下のコマンドではfind_packageコマンドによって作成された変数をプロジェクトに設定しています。 これらのコマンドは同じ階層全体に反映されます(CMakeLists.txtをディレクトリごとに作成し、上位階層から読み込ませることでプロジェクトを階層で分けることができます)。 add_definitions include_directories link_directories

add_definitionsの動作はいまいちわかっていません。 include_directoriesはC/C++のインクルードディレクトリを設定しています。 link_directoriesはC/C++のビルド時にリンクするファイル群のディレクトリを設定してしています。

add_executableコマンドは実行ファイルを作成するためのコマンドです。 第一引数が生成される実行ファイルの名前、第二引数以降は実行ファイルを生成するのに必要なソースファイルです。 この第一引数はtarget_link_librariesの第一引数にも使われます。

target_link_librariesではlink_directoriesで設定したディレクトリ内のリンクするファイルを設定しています。 このコマンドは先に説明したadd_definitionsなどとは異なり、一つのプログラムごとに設定するコマンドになります。 なので、どのプログラムに設定するかを指定する必要があります。 ここでは第一引数にadd_executableの第一引数で指定した名前を記述しています。

set(CompilerFlags...以下のコマンドはOpenCV3.0を使っている場合に必要な特別な記述です。 僕が作成した記事ですが、詳しくはこちらをご覧ください。 kyokushin.hatenablog.com

あとはCMakeで実行→ビルド

これらの設定を記述し、CMakeコマンドもしくはCMakeのGUIプログラムで実行するとMakefileやソリューションファイルが生成されます。 設定に間違いがなければビルドが正常に完了し、実行ファイルが出来上がるはずです。

CMakeを使うことの本質的なメリット

CMakeはプラットフォームの異なる環境でのビルドを容易にするために作成されたツールであるため、一つのCMakeLists.txtを作成するだけでUnixWindowsでビルド可能なファイル群を生成してくれます(複雑なプログラムだと環境ごとに分岐が必要になる場合もあります)。 もちろんMacもできるはず(Macユーザーではないのでしらない) ローカルではWindows、サーバーはLinuxというような開発をしている人でも同じファイルをローカルとサーバー間で共有できるため、わざわざサーバーにログインせずともローカルで開発し、開発が終わったらそれをサーバーにアップする、というような行程でのプログラミングも可能になります。 CMakeを使うことでプラットフォーム毎に設定を書くという二度手間が必要なくなり、さらに柔軟な開発スタイルを選択できるという大きなメリットを得ることができるのです。

最後に

駆け足でCMakeを使ったビルド方法について説明してみました。 いかがだったでしょう?CMakeの魅力に気付いていただけたでしょうか?

今回の記事は僕自身のための覚書として書きました(毎回そうなのですが) なので分かりにくい点が多々あると思いますが、質問があればコメントに書いていただければと思います。

今回はここまで。