ねののお庭。

かりかりもふもふ。

CMakeで外部ライブラリとリンクさせたりするのどうすんのという話。

どうも、今までVC++書いてきていたので、ライブラリとかをビルドするときにCMakeとか使っていたものの、Visual StudioのおかげでmakefileとかCMakeListsなどは書かないで過ごしてきた人です。

しかし最近Linux(Ubuntu)上でC/C++書きたくなったのでCMake書くことになり。
どうすんだ?これ。
と途方にくれたのでやり方とかいろいろ書いておきます。

私のやることは相変わらずOpenCVで遊ぶ、なので具体例としてOpenCVでやっていますが、外部のライブラリをつなげる要領はなんでも同じだと思います。

今回は自作のプログラムにOpenCVを組み込むところまでをやっていきたいと思います。

こう書けばビルドできまっせ〜みたいな記事はたくさんあるんだけど正直CMake入門者的にはなにやってんだこいつ的な感じなので(私はそうだった)基本的なとこから理解できるような感じで書いていきます。

やることは簡単

まぁvisual studioでやる場合もcmakeでビルドする場合もやることは同じで

includeディレクトリの指定 ライブラリディレクトリの指定 ライブラリの指定 です。これをどう記述していくかってだけの話ですね。

Visual Studioの時の設定。

まずプロジェクトのプロパティからこんな感じで設定しますよね。

ライブラリのdllにパスを通してから以下の3つを設定しますよね。

include libdir lib

私の場合全部ベタ書きです。


Linuxだとどうするの〜

まずcmake以前のお話です。

C++をビルドするのにg++を使いますよね。そこではmain.cppに全部記述されてた場合にopencvを使おうとすると次のようにコマンドを叩きます。

g++ main.cpp -I/usr/local/include -L/usr/local/lib -lopencv_cudabgsegm -lopencv_cudaobjdetect -lopencv_cudastereo -lopencv_dnn -lopencv_ml -lopencv_shape -lopencv_stitching -lopencv_cudafeatures2d -lopencv_superres -lopencv_cudacodec -lopencv_videostab -lopencv_cudaoptflow -lopencv_cudalegacy -lopencv_calib3d -lopencv_features2d -lopencv_highgui -lopencv_videoio -lopencv_photo -lopencv_imgcodecs -lopencv_cudawarping -lopencv_cudaimgproc -lopencv_cudafilters -lopencv_video -lopencv_objdetect -lopencv_imgproc -lopencv_flann -lopencv_cudaarithm -lopencv_core -lopencv_cudev

ぱっとみ長いですけど、opencvのライブラリ全部繋げてるので長く見えてるだけです。

g++のオプションの説明をしておくと、

  • -I:インクルードディレクトリの指定
  • -L:ライブラリディレクトリの指定
  • -l:ライブラリの指定 です。これを毎回手打ちするだけでもまぁビルドできなくはないです。これをもっと短く書くと

``g++ main.cpppkg-config --cflags opencvpkg-config --libs opencv`

のようにもかけます。

```echo `pkg-config --libs opencv`

とか打ってみるとなにやってるかわかると思います。

CMakeかくよ〜

で毎度これをうつのはめんどくさいのでCMake書きましょうという話になります。

全部ベタ書きで書くとこうなります。

cmake_minimum_required(VERSION 3.5.1) # cmakeの最小のバージョンを決めて 
project(Main) # プロジェクト名を決める 
set(CMAKE_CXX_STANDARD 14) # C++14で書くよCMakeに教えてあげる 
include_directories(/usr/local/include) #インクルードディレクトリ指定 
link_directories(/usr/local/lib) #ライブラリディレクトリ指定 
add_executable(Main main.cpp) #吐き出す実行ファイルと使うソースコードの指定 
target_link_libraries(Main opencv_cudabgsegm opencv_cudaobjdetect opencv_cudastereo opencv_dnn opencv_ml opencv_shape opencv_stitching opencv_cudafeatures2d opencv_superres opencv_cudacodec opencv_videostab opencv_cudaoptflow opencv_cudalegacy opencv_calib3d opencv_features2d opencv_highgui opencv_videoio opencv_photo opencv_imgcodecs opencv_cudawarping opencv_cudaimgproc opencv_cudafilters opencv_video opencv_objdetect opencv_imgproc opencv_flann opencv_cudaarithm opencv_core opencv_cudev) # 使うライブラリの指定。add_executableの後に書かないとダメ。

わざわざコメント書くまでもない感じですが、こうなります。

こんな感じで書いておいて

$ls 
main.cpp CMakeLists.txt 
~$mkdir build 
~$cd build 
~/build$cmake ../ 
~/build$make

という感じにするとコマンド叩くとビルドできます。buildとかディレクトリいちいち作ってるのはout-of-sorceとかいってcmakeコマンドで吐き出されるものをbuildの中にして、ソースコードと分離させるためですね。ちなみにhoge.cppというソースもあるんやが〜〜という場合は

add_executable(Main main.cpp hoge.cpp)

という感じでadd_executableに書き足していけばいい感じです。

これで最低限度でCMakeを使って外部のライブラリをリンクしてビルドできるようになりました。

でもベタ書き嫌〜〜

ベタ書き嫌ですよね。普通は。なので次のようにもかけます。

cmake_minimum_required(VERSION 3.5.1) # cmakeの最小のバージョンを決めて 
project(Main) # プロジェクト名を決める。 
set(CMAKE_CXX_STANDARD 14) # C++14で書くよCMakeに教えてあげる。 
find_package(OpenCV REQUIRED) #OpenCV見つけてきて 
include_directories(${OpenCV_INCLUDE_DIRS}) #インクルードディレクトリ指定 
add_executable(Main main.cpp) #吐き出す実行ファイルと使うソースコードの指定 
target_link_libraries(Main ${OpenCV_LIBRARIES}) #ライブラリとリンク

めちゃくちゃ完結にかけます。でこれがOpenCVとかCMake使ってビルドしたいけどどう書くんや!?というときに検索にヒットするもの。ぶっちゃけ雰囲気はわかるけどfind_packageとかどうやって動いてんの!?は!?という感じに最初陥りました。陥りますよね多分普通は。

find_package()の動作についてはあとで軽く書きますが最初にかる〜く説明すると

find_package(OpenCV REQUIRED)でOpenCVを探してきて、それらの情報を取得します。取得した情報はOpenCV_INCLUDE_DIRS,OpenCV_LIBRARIESなどの変数に格納されます。REQUIREDはこのソースビルドするのに必ず必要だかんね!という意味合いです。 ${}の中に変数を書いてあげて、includeやtarget_linkなどの設定に食わせます。 そうするとビルドできるようになります。簡単。

message("${OpenCV_INCLUDE_DIRS}")

とかすると変数の中身が見える。

find_package()isなにもの

こいつは前述のとおり必要なライブラリとか見つけてくれる便利なヤツなのですが、どのようにライブラリ見つけてくるかという話が気になるところです。こいつにはモジュールモードとコンフィグモードの2種類があって、それぞれ違った感じで探索してくるようです。モジュールモードは

/usr/share/cmake-*/Modules

内のFind.cmakeってファイルを探してきてるみたいですね。Find.cmakeの中身見てあげるとCMakeLists.txt上で使える変数使える変数がいろいろ書いてあります。

でコンフィグモードは*Config.cmakeってファイルを探しているらしい。

OpenCVはコンフィグモードで探索されているっぽく、私の環境では/usr/local/share/OpenCV/OpenCVConfig.cmakeというファイルをみているようでした。

cmake .. -DCMAKE_FIND_DEBUG_MODE=1

とかのオプションつけてcmakeコマンドうつとどこを見ているのかを教えてくれます。

でコンフィグモードがどこを探索しているのか〜という話なのですが。

詳しくはここらへんの記事に書いてあるのですが、いろいろと探索しているようです(雑)


しれっとpkg-configとか上で使ってるけどこれはなに。

cmakeとは関係のないライブラリの管理ツールです。ライブラリインストール時に*.pcというのが指定のパスに配置されてそこにいろいろ情報があるみたいです。

wikiとかにどこを参照してるかとかの話が書いてあるので、みるとなるほど〜ってなります。

参考

http://www.wagavulin.jp/entry/2017/02/20/082608 https://qiita.com/osamu0329/items/bd3d1e50edf37c277fa9 https://ja.wikipedia.org/wiki/Pkg-config