注意:この記事は古くなっています。この記事を書いた人は、現在Windowsでの開発をしていないため、最新の状況を把握していません。
Visual C++ での CMake プロジェクト
という記事がMicrosoftから公開されています。
CMakeLists.txtを書くことで、VisualStudioの設定が楽になることがわかったので、再検索しなくて済むようにメモを書く。
(Visual Studio の各バージョンごとに vcxproj を用意して… というのが辛くなったため、 CMake によるプロジェクト生成という流派にちょっと入門してみました。2017/6/16 の記事 を見つけました。VisualStudioの設定を楽するためにCMakeを使い出す人が増えているようです。)
(CMakeLists.txtの書き方については、もっと適切な記事があるはずなので、そちらを利用したい)
- cmake の使い方
- CMake 簡易まとめ
- OpenCV3.1.0でSIFTとかSURFとかBINGを使う
- OpenCV3.1.0をCMakeを用いてbuildする
- [find_packageの動作]
(http://qiita.com/osamu0329/items/bd3d1e50edf37c277fa9) - [お手軽な xxx-config.cmake の作成方法]
(http://qiita.com/osamu0329/items/134de918c0ffa7f0557b) - CMake: 条件分岐
#VisualStudioの設定の憂鬱
WindowsでVisual Studioを使ってC++開発をする際に次のわずらわしい点がある。
- Visual Studioのバージョンによってソリューションファイルの記述が異なり、Visual Studioの設定が共有できない。
- OpenCVのバージョンが異なるたびにVisualStudioの各Projectに対してDebugモード、Releaseモードの両方にわたって、設定します。
[Build][Properties][Debug] [Configuration] [VC++ Directories][Include Directories]
それと[Library Directories]にOpenCVのインストールされているディレクトリを各人ごとに書くのが面倒です。 - C++のソースコードにライブラリのバージョンを記述することも避けたいことです。
#pragma comment(lib, "xxx.lib")
これらの問題点は、CMakeLists.txtを記述してcmakeを使えば解決できます。
そこでCMakeLists.txtの書き方を他のページを参照しながら示します。
#CMakeLists.txtの書き方
この例ではaviDetector.exeを aviDetector.cppから作成する例です。
${PROJECT_HOME}/
aviDetector.cpp
の時は以下の2行を書くだけでOK:
cmake_minimum_required(VERSION 2.8)
add_executable(aviDetector aviDetector.cpp)
次に、OpenCVのライブラリを使うための設定を参照します。
Pythonのライブラリとリンクする場合の設定を追加しました。
cmake_minimum_required(VERSION 3.8)
# プロジェクト名を指定する
project(aviDetector)
# 次の行を追加するとMinSizeRelとRelWithDebInfoの選択肢を生成することが抑制できます。
set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "limited configs" FORCE)
add_executable(aviDetector aviDetector.cpp)
# C++11
target_compile_features(aviDetector
PRIVATE cxx_std_11
)
# マクロ定数WITH_SOMELIBを追加
target_compile_definitions(aviDetector
PRIVATE WITH_SOMELIB
)
# OpenCVのパッケージを探す
find_package(OpenCV REQUIRED)
find_package(PythonLibs REQUIRED)
# OpenCVが見つかった場合のみ設定を行う
if(OpenCV_FOUND)
# インクルードパスを指定
target_include_directories(aviDetector
PRIVATE
${OpenCV_INCLUDE_DIRS}
${PYTHON_INCLUDE_DIRS}
)
# リンクするライブラリ指定
target_link_libraries(aviDetector
${OpenCV_LIBS}
${PYTHON_LIBRARIES}
)
endif(OpenCV_FOUND)
CMakeLists.txtさえ書いてあれば、
あとはCmakeを使って[configure][generate]するだけです。
*.sln, *.vcxprojのファイルができあがりです。
最近のOpenCVをbuildした人にはご存知のとおりです。
追記:OpenCVの公式サイトでのCMakeについての記載
Using OpenCV with gcc and CMake
<追記:プリプロセッサ用のマクロの定義をCMakeLists.txtで行う>
次のような記載をCMakeLists.txtに追加します。
add_definitions(-DWITH_OPENCV2)
コンパイラに対して
-DWITH_OPENCV2
オプションをつけて実行することに対応します。
<追記>
#OpenCV3系統とOpenCV2系統の両立
このようにして書いておけば、CmakeでOpenCV_DIRで今回のターゲットとするバージョンのあるディレクトリを指定すれば、OpenCV2系統、OpenCV3系統にも共通の設定にできる。
OpenCV3系統でbuildすると、C++スタイルになりきっていないコーディングの部分でbuildに失敗します。その場合にはC++スタイルになるように記述の違いを検索して調べて、C++スタイルで書き直します。C++スタイルで書き換えたソースコードは、OpenCV2系統でもbuild できます。
OpenCV2のサンプルコードではC++スタイルとCスタイルとが混在していたり、
using namespace cv;
の記述があったりします。
今後のメンテナンスを考えると using namespace cv;
は使わないようにしておくのがよさそうです。
OpenCV4ではC++11が前提に (追記)
C++11になることで、より洗練された安全な書き方に集中されるようになっていきます。
次の1行をCMakeLists.txt に含めておく。
add_definitions(-std=c++11)
###Boostの設定を追加する
まずはBoostの本家のサイトでBoostをCMakeLists.txtに書く変数のリストをみてみよう。
find_package
をした後に
${Boost_INCLUDE_DIRS}
といった変数がCMakeLists.txtで参照できるようになります。
FindBoost
https://cmake.org/cmake/help/v3.0/module/FindBoost.html
以下のstackoverflowの記事などを参考にしてみることとしよう。
How do you add boost libraries in CMakeLists.txt
###OSの違いをCMakeLists.txtに反映させる
CMakeで大きめのプロジェクトを構成するためのメモ
の中に、
if(WIN32)
に始まる記述があります。
if(APPLE)
に始まる記述もあります。
if(UNIX)
もできるようです。
以下のような記述もできます。
if(EXISTS src/a.cpp) # src/a.cpp というパスが存在しているかどうか
####追記:
CMakeLists.txtから作ったソリューション、プロジェクトファイルの不満(Visual Studio)
・不満1:vcxprojファイルに書かれるファイル・ディレクトリのpathが絶対pathであること。
・不満2:作ったソリューションの設定が、その後もCMakeLists.txtによって自動更新がかかってしまうこと。
・不満3:プロジェクトの設定のほぼ全てをCMakeLists.txtから行いたいが、まだその書き方を習得していない点
・不満4:何も指定しないとmultibyteの文字コードがVisualStudio用に生成され、Unicodeに手作業で直す必要を生じる。
#####不満1への対策
次のようなスクリプトで、pathの設定をファイルからの相対パスに書き換える。
# -*- coding: utf-8 -*-
# pylint: disable-msg=C0103
"""
convert absolute path to relative path
"""
import os, string, glob, shutil
names = glob.glob("*.vcxproj")+glob.glob("*.vcxproj.filters")
cwd = os.getcwd()
cwd2 = string.join(string.split(cwd, os.path.sep), "/")
for p in names:
print p
shutil.copy(p, p+".bak")
data = open(p, "rt").read()
data = data.replace(cwd, ".")
data = data.replace(cwd2, ".")
oname = p
open(oname, "wt").write(data)
以下のページにある解説を参考にすれば、すんなり相対パスの記述ができるようだ。
RELATIVE_PATH
基準となるパスからの対象のパスへの相対パスを変数に格納します。
#####不満2への対策
Solution Explorer中の
[CMake Rules]を右クリックで[delete]することで解消する。
#####不満3への対策
インクルードパスを指定するときはinclude_directoriesコマンドを使う。
ライブラリの追加
target_link_libraries(myapp foo)
ライブラリパスの指定
link_directories(/path/to/lib)
#####不満4への対策
以下の行を追加するとVisualStudioでもunicodeのライブラリをリンクするようになる。
add_definitions(-D_UNICODE)
追記:
CMakelists.txt をUTF-8で保存するときにはBOMをつけないことが必要なようです。
[Unable to parse CMakeLists.txt in UTF-8 with BOM encoding]
(https://public.kitware.com/Bug/print_bug_page.php?bug_id=11137)
参照したURL
「ごく簡単なcmakeの使い方」
http://qiita.com/termoshtt/items/539541c180dfc40a1189
「初めてのOpenCV開発 ― Visual Studio/CMake/NuGetでプロジェクト作成【OpenCV 2.4.9】」「CMake設定ファイル作成」
http://www.buildinsider.net/small/opencv/03
「CMakeを使ってOpenCVを楽にセットアップする方法 (for Visual Studio 2010)」
http://sky-y.hatenablog.jp/entry/2014/05/23/143722
「CMakeを使ってみた(2)もう少しまともなプロジェクト」
http://wagavulin.hatenablog.com/entry/2011/11/27/222642
CMake チュートリアル
http://opencv.jp/cmake/cmake_tutorial.html
CMake: 便利なコマンド・変数
http://qiita.com/mrk_21/items/5e7ca775b463a4141a58