🥒

[C++] OpenCVをCMakeのFetchContentで依存解決する

2023/06/03に公開

とりあえずのあっさりメモ。

背景

OpenCVを自分でビルドして使う場合、事前にビルドしておくのが大前提になっています。

ところで最近のCMake (3.11以降)では、FetchContentという革命的な代物が導入されていて、対応しているライブラリならばCMakeLists.txtに数行書くだけで簡単に依存解決可能です。例えばfmtを導入したい場合はこれだけです。

include(FetchContent)
FetchContent_Declare(
    fmt
    GIT_REPOSITORY https://github.com/fmtlib/fmt.git
    GIT_TAG 9.1.0)
FetchContent_MakeAvailable(fmt)

こんな感じでOpenCVもFetchContentできないかという話です。

環境

少なくとも、OpenCV 4.6.0や、開発中の5.xブランチでは動作するようです。

おことわり

この記事で述べる方法は2023年6月現在、OpenCVとして公式にサポートされるものではありません。alalek先生曰く:
https://github.com/opencv/opencv/issues/20548#issuecomment-898290169

This build mode is not supported. There are no plants to support that.
Prebuild OpenCV separately and use find_package(OpenCV)

方法

実際のところただ参照して終わりですが 🙇‍♂️

OpenCVのビルド構成を変えることも変数指定により可能という点を追加で示しています。

CMakeLists.txt
cmake_minimum_required (VERSION 3.11)

project ("OpenCVSample")

add_executable (OpenCVSample "main.cpp")

set_property(TARGET OpenCVSample PROPERTY CXX_STANDARD 20)

include(FetchContent)
FetchContent_Declare(
    opencv
    GIT_REPOSITORY https://github.com/opencv/opencv.git
    GIT_TAG        5.x
)
# OpenCVのCMakeで与える変数の指定
set(BUILD_EXAMPLES "OFF")
set(BUILD_DOCS "OFF")
set(BUILD_PERF_TESTS "OFF")
set(BUILD_TESTS "OFF")
set(BUILD_LIST "core,imgproc,imgcodecs")
FetchContent_MakeAvailable(opencv)

target_include_directories(OpenCVSample PRIVATE
    ${OPENCV_CONFIG_FILE_INCLUDE_DIR}
    ${OPENCV_MODULE_opencv_core_LOCATION}/include
    ${OPENCV_MODULE_opencv_imgproc_LOCATION}/include
    ${OPENCV_MODULE_opencv_imgcodecs_LOCATION}/include
)
target_link_libraries(OpenCVSample opencv_core opencv_imgproc)

target_include_directories のところが必要という点だけ注意です。

利用するコードの例です。どうも普段と#includeの具合は少し変わりまして、例えば<opencv2/opencv.hpp>は解決できません。CMakeLists.txtのtarget_include_directoriesで追加の指定が要るのだろうと思いますがまだわからず。例示したcv::getTickCountの場合は以下のようにopencv2/core/utility.hppという普段意識しないであろう深めのヘッダを引っ張ってくることになります。他にも例えばcv::Matならばopencv2/core/mat.hppなど。IDEの補完に頼ればそんなには困らないと思いますが。

main.cpp
#include <iostream>
#include "opencv2/core/utility.hpp"

int main()
{
    std::cout << "TickCount = " << cv::getTickCount() << std::endl;
    return 0;
}

使用上の注意点

総じて、事前ビルド方式がやはり無難です。OpenCV以外でも、たとえばboostも一苦労あるようで、大きなライブラリには不向きなのかもしれません。シンプル・単機能なライブラリ向けにはよく適合します。

  • 前述のように#include指定が煩雑になります。CMakeLists.txtの制御もおまじない感があります。
  • 少しCMakeLists.txtに手を加える度、OpenCVのCMakeも走ってしまいます。キャッシュが効くのでそう遅くないですが、時々リビルドまで走ってしまうとしばらく手を止める羽目に。
  • opencv_contribを併用したい場合、試していないのですが厳しそうな予感が。

有効なシーン

ただ、事前ビルドはフットワークが重い(初回めんどくさい)のは間違いなく、さくっと試したい時だとか[1]、サンプルコードを配布したい時などでは有用だと思いました。CMake以外の追加の依存無しに動作可能なのが良いですね。

Visual Studioも最近はCMakeをサポートしています。(OpenCVで使うかはさておき、)FetchContentの恩恵にあずかるには、たとえWindows限定の実装であろうとも.vcxprojは卒業してCMakeに一本化するのが良いのだろうと思っています。

脚注
  1. もちろん、OpenCVのような著名ライブラリならばaptやvcpkg等のパッケージマネージャで導入できるわけで、自分でビルドしたい理由がない限りその方が更に楽でしょう ↩︎

Discussion