空飛ぶ気まぐれ雑記帳

主に趣味とかプログラミングについて扱います。

Visual Studioユーザーに送るCMakeテクニック☆ (2)

Visual Studioユーザーに送るCMakeテクニック☆ 、第二回目です。
今回は、昨日の記事で説明したフィルタリング機能を使って、CMakeファイルをVisualStudioから簡単に見えるようにしようって話です。
具体的にはどういうことかと言うと下記のように各ディレクトリに配置されているCMakeListsと*.cmakeファイルをディレクトリ構造をフィルタ名としたCustomプロジェクトを作成します。

f:id:elda27:20161130000643p:plain

下記が実際のソースコードです。

FILE(GLOB_RECURSE CMAKE_LIST_FILES CMakeLists.txt *.cmake)

FOREACH(file ${CMAKE_LIST_FILES})
  FOREACH(dir ${CMAKE_CURRENT_LIST_DIR})
    FILE(RELATIVE_PATH relative ${CMAKE_CURRENT_LIST_DIR} ${file})
    
    STRING(REGEX MATCHALL "[^/]+" filters "${relative}")
    LIST(LENGTH filters output_length)
    MATH(EXPR iteration "${output_length} - 2")
    
    IF(${iteration} LESS 0)
      continue()
    ENDIF()
    
    SET(group_string "")
    FOREACH(i RANGE 0 ${iteration})
      LIST(GET filters ${i} g)    
      set(group_string "${group_string}\\${g}")
      #MESSAGE(${i},${output_length}:${g})
    ENDFOREACH()
    SOURCE_GROUP("${group_string}" FILES ${file})
  ENDFOREACH()
ENDFOREACH()

ADD_CUSTOM_TARGET(CMakeLists SOURCES ${CMAKE_LIST_FILES})
<||

Visual Studioユーザーに送るCMakeテクニック☆ (1)

はじめに

今月忙しすぎてブログの更新が滞っていたので、暫くごまかしのためにCMakeのテクニックを紹介します。
なお、未だに忙しくて録に記事が書ける状態ではないので記事は分割してますが、悪しからず。

決して当初掲げていた週一更新の分を一気に放出しようとしているわけではありません

それはさておき、今日紹介するのはVisual Studioが有するフィルタリング機能をCMakeから利用するにはどうすれば良いのか?
という話です。

フィルタリング機能って

Visual Studioでプロジェクトを右クリックしてでてくるポップアップメニューの Add > New Filterで出てくるアレです。
デフォルトでも、Source filesやHeader files(日本語版だとソースファイルとヘッダーファイルかな?)というものが設定されているかと思います。

このフィルタリング機能ですが、これがないとソースファイルの数が100近くなると非常に見づらくなるので、どっぷりとVisual Studioを使っている方は間違いなく利用しているかと思います。

これをCMakeを使ってソリューションファイルを生成するとデフォルトのSource filesやHeader filesのフィルタリングすらないため、非常に不便ですよね。

フィルタリングを有効にする

下記コマンドを実行すればフィルタリングが有効になります。
なお、デフォルトでSource filesとHeader filesが設定され、振り分けられます(久しくデフォルトの挙動を確認していないので不安ですが…)。

SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON) 

もし、これをONにしない場合、以下で説明している設定をしても反映されないので注意しましょう

ソースファイルをフィルタリングしたいとき

ソースファイルをフィルタに分類する場合、下記コマンドを実行すればOKです。

SOURCE_GROUP("任意のフィルタ名" FILES <ソースコードのファイルパス> ...)

なお、もしフィルタをネストする場合、例えば Source files > hoge > huga > hage.cpp のような階層構造を持たせたい場合、フィルタ文字列をバックスラッシュ2つ(文字列内の場合バックスラッシュをエスケープする必要がある?)並べる必要があります。

SOURCE_GROUP("Source files\\hoge\\huga" FILES hage.cpp)

のようになります。

プロジェクトをフィルタリングしたいとき

プロジェクトの場合ソースコードとは違う方法でフィルタリングを行います(フィルタリングのフォーマットは同じ)

SET_TARGET_PROPERTIES(<プロジェクト名(ターゲット名)> PROPERTIES FOLDER "任意のフィルタ名")

ここで注意しなければならないのが、ターゲットを対象としてフィルタリングするため、add_executable or add_library or add_custam_target etc... でターゲットを生成した後に呼び出す必要があるという所。

おわりに

ざっくりとCMakeを使ったフィルタリングの使い方を説明しました。
次回以降も個人的に知ってて便利だな―と思ったCMakeの使い方を説明していくつもりです。

なお、全五回くらいになる予定していますそんなにネタがあるか微妙ですが

Visual Studio で拡張子のないC++ヘッダーをIntelli Senseで表示する方法

Qt+CMakeを使いつつVisual Studioを使っていると拡張なしのヘッダーファイルをインクルードしたい時がある(実際には拡張し有りのヘッダーファイルをインクルードすれば事足りるので特に問題にはならないが…)。
その場合、なぜかIntelli Senseでは標準ライブラリ以外の拡張子無しのヘッダーファイルが候補として表示されることはない。

本当になぜかは分からないが…

それはさておき、解決方法。
Tools > Options... から設定画面を開く。
それから TextEditor > FileExtension から拡張子に関する設定画面を開く。
その後,「Editor:」と「Map extensionless files to:」をMicrosoft Visual C++に変更して、チェックボタンをチェックしてからOKボタンをクリックして設定完了。

f:id:elda27:20161129232257p:plain

Windowsでffmpegを使ってみた話

はじめに

ffmpegを使ってみた話ですが、あくまでもC++から使ってみようっていう話。
ffmpegバイナリを使うって話はググれば山ほど出てくるんだけど、Cのライブラリを使うって言う話はあまり出てこなかったので、備忘録を兼ねて。

そもそも、どうしてffmpegを使おうと思い至ったかと言いますと、OpenCVのVideoCaptureってコーデックが揃った外部のffmpegを指定してもフレームのシークや動画情報の取得が上手く行かない場合が多く、そもそもコーデックに対応してないなんて場合もあって微妙に使いづらいという問題があります。(汎用的な機構でいろんな動画フォーマットを開けるというだけで十分便利なのですがね)

それで、ffmpegを直接使えば多少の手間はかかれど、そういう問題はないだろうと思い、実際に試してみました。

準備

いつも通り、Windows環境での話しかしませんので、MacLinuxの人はパッケージマネージャーで適当に準備してください。
それで、Windows環境の場合ですが一からffmpegをビルドするのは大量のコーデックをビルドする必要があって、かなり骨が折れるので下記からダウンロードしてきましょう。
32bit、64bit、好きな方を選んで、SharedとDevの両方のパッケージをダウンロードしましょう。なぜかはわかりませんが、Devを選択してダウンロードしてくるとリンクするシンボルが含まれたlibファイルはあるのにdllがないのでSharedパッケージに含まれるdllを併せて利用します。

Builds - Zeranoe FFmpeg

テストコード

下記のサンプルコードを改変してC++で使えるようにしました。ただ、それだけだと面白みが無いので、フレームのシークをできるようにてみました。(正しく動いているとは言ってない)
ffmpeg tutorial

ポイントは、ffmpegのヘッダーを extern "C" で括ってやることぐらいですかね。
ただ、このコード。たまにシーク出来ないことがあるので、おそらくどこか間違ってるんでしょうね。おいおい修正します。

gist.github.com

cygwinでFindOpenCVするとエラーになる

やんごとなき事情により、cygwincygwinでcmakeを使う必要がでてきたのだけれども、FindPackageでapt-cygでインストールしたOpenCVを探すとエラーが出た。

以下は実際のエラー出力

CMake Error at /lib/cmake/opencv/OpenCVModules.cmake:124 (message):
The imported target "opencv_core" references the file

"//lib/libopencv_core.dll.a"

but this file does not exist. Possible reasons include:

* The file was deleted, renamed, or moved to another location.

* An install or uninstall procedure did not complete successfully.

* The installation package was faulty and contained

"/lib/cmake/opencv/OpenCVModules.cmake"

but not all the files it references.

Call Stack (most recent call first):
/lib/cmake/opencv/OpenCVConfig.cmake:71 (include)
util/CMakeLists.txt:5 (find_package)

それで、その原因となるコードを追っかけると原因はOpenCVModules-relwithdebinfo.cmakeにあった。
以下はその1行目から17行目を抜粋したコード

#----------------------------------------------------------------
# Generated CMake target import file for configuration "RelWithDebInfo".
#----------------------------------------------------------------

# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)

# Import target "opencv_core" for configuration "RelWithDebInfo"
set_property(TARGET opencv_core APPEND PROPERTY IMPORTED_CONFIGURATIONS RELWITHDEBINFO)
set_target_properties(opencv_core PROPERTIES
  IMPORTED_IMPLIB_RELWITHDEBINFO "${_IMPORT_PREFIX}/lib/libopencv_core.dll.a"
  IMPORTED_LINK_INTERFACE_LIBRARIES_RELWITHDEBINFO ""
  IMPORTED_LOCATION_RELWITHDEBINFO "${_IMPORT_PREFIX}/bin/cygopencv_core-2.4.dll"
  )

list(APPEND _IMPORT_CHECK_TARGETS opencv_core )
list(APPEND _IMPORT_CHECK_FILES_FOR_opencv_core "${_IMPORT_PREFIX}/lib/libopencv_core.dll.a" "${_IMPORT_PREFIX}/bin/cygopencv_core-2.4.dll" )

つまるところ/lib/opencv_core.dll.aに探したいライブラリがあるんだけど、_IMPORT_PREFIXが/の場合//lib/opencv_core.dll.aに成ってしまっているというのが問題です。本来Linuxでは/をいくつ重ねても許容されますが、cygwinでは//がWindows環境における\\と同一の意味として解釈されるため、libとういう名前のサーバー無いためエラーとなります。

というわけで、このコードの8行目に以下のコードを追加して末尾の/を削除するように変更。

string(REPLACE "/" ";" _IMPORT_PREFIX_TEMP ${_IMPORT_PREFIX})
list(LENGTH _IMPORT_PREFIX_TEMP _IMPORT_PREFIX_LENGTH)
SET(_IMPORT_ITERATION_COUNT 2)
while(${_IMPORT_ITERATION_COUNT} LESS ${_IMPORT_PREFIX_LENGTH})
  math(EXPR _INSERT_POSITION "${_IMPORT_ITERATION_COUNT} - 2")
  list(INSERT ${_INSERT_POSITION} ${_IMPORT_ITERATION_COUNT} "/")
  math(EXPR _IMPORT_ITERATION_COUNT "${_IMPORT_ITERATION_COUNT}+1")
endwhile()

string(CONCAT _IMPORT_PREFIX ${_IMPORT_PREFIX_TEMP})

unset(_INSERT_POSITION)
unset(_IMPORT_PREFIX_TEMP)
unset(_IMPORT_PREFIX_LENGTH)
unset(_IMPORT_ITERATION_COUNT)

結構アドホックな気がするけど、急ぎの案件だったのでとりあえず、これで解消しました。
同じ症状に陥って、他にこうしたらなんかCMake通ったよみたいな人いたら教えて欲しいです。

DLIB with CUDAでCNNを使ってみた in Windows

はじめに

下記の記事を書いてて、うぉぉぉぉってなってそのままDLIBのコンパイルをやりなおしました。

elda27.hatenablog.com

DLIBのコンパイル

DLIBのCUDAを有効にするためには、CUDA 8.0(RC版じゃないですよ)とcuDNN 5.0以上が必要です。また、Windowsも64bit環境でなければならないので注意してください。
まず、cuDNNは下記のURLからダウンロードしてください。バージョンは5.0でも5.1でもどっちでも構いません。

cuDNN
developer.nvidia.com

このcuDNNを適当な所に解凍し、さらに以下のCMakeを実行します。

cmake -DCOMPILER_CAN_DO_CPP_11=ON -DCMAKE_PREFIX_PATH=<cuDNNのルートディクレトリ> <dlibのルートディレクトリ>

ただし、このままだとコンフィギャレーションエラーが出るので、以下の様に"dlib/cmake_utils/test_for_cudnn/find_cudnn.txt"を以下のように書き換えます(githubリポジトリにある最新版のdlibを使う場合、このバグは修正済みなので飛ばしてOK)。

message(STATUS "Looking for cuDNN install...")
# Look for cudnn, we will look in the same place as other CUDA
# libraries and also a few other places as well.
find_path(cudnn_include cudnn.h
    HINTS ${CUDA_INCLUDE_DIRS} ENV CUDNN_INCLUDE_DIR  ENV CUDNN_HOME
    PATHS /usr/local ENV CPATH
    PATH_SUFFIXES include
    )
get_filename_component(cudnn_hint_path "${CUDA_CUBLAS_LIBRARIES}" PATH)
find_library(cudnn cudnn
    HINTS ${cudnn_hint_path} ENV CUDNN_LIBRARY_DIR  ENV CUDNN_HOME 
    PATHS /usr/local /usr/local/cuda ENV LD_LIBRARY_PATH
    PATH_SUFFIXES lib64 lib x64
    )
mark_as_advanced(cudnn cudnn_include)

これでコンパイルすれば、無事CMakeも通ると思います。

サンプルコード

ソースコードの内容は前と代わりませんがCUDAを使用する場合はcmakeオプションに"-DUSE_CUDA"オプションを追加してください。

github.com

結果

推定精度は前回と同じなんだけど、実行時間(学習時間)が爆速になりました。
以前は学習に2日程かかっていたものが20sで終わるようになりました(GTX 970で実行)
まあ、DLIBではそもそもCPUにおける並列化すらしていないようなので当たり前といえば当たり前ですが。

CUDA 8.0がいつの間にかリリースされててVisual Studio 2015 Update 3でも使えるようになっていた話

CUDA8.0 RCがリリースされたのが4月頃だったと思うが、それから半年。CUDA8.0がいつの間にかリリースされていた。
ダウンロードは下記から。

developer.nvidia.com

さて、このCUDA 8.0の何がスゴイかと言うとCuda8.0 RC では未対応だったVisual Studio 2015 Update 2以降に対応しているという点だ。
これで、DLIBをコンパイルできれば、Windows環境でGPGPUを使ったDNNがまともに使えるかもしれない。

とりあえず、サンプルをコンパイルして動作を確認するところまでは出来たので、今後DLIBのコンパイルをやっていきたい。

追記

下記によると、CUDA8.0は9/28にリリースされたらしい。
知らなかった。

gihyo.jp