空飛ぶ気まぐれ雑記帳

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

OpenCV 4.2.0のビルドエラー対策

未だにこのブログを見る人がいたのと気が向いたので更新しています。

この記事はカスだ

とりあえず、OPENCV_PYTHON3_VERSIONはBOOLではなく、STRINGで指定するものだ。 しかも普通にバージョンを指定すべき変数だ。 少なくともOpenCV 3.4のブランチを見るとOPENCV_PYTHON3_VERSIONはPython3のバージョンを指定するための変数だった。 世間にあふれる情報が正しいとは限らないということを改めて感じたので、戒めに記事事態は残しておく。

というか、解決策気づいてから同じ変数が二つ並んでいるのに気づかんかったのか。。。

最近の困りごと

なぜかOpenCVをビルドする機会があって、armv7でビルドするとエラーがでないのに、x64でビルドするとcmakeエラーがでるという不具合に見舞われて怒っていた。 より具体的に言えばPython3向けのopencvをビルドしようとするとエラーが出るという話であるが。 再現可能なDockerfileは以下の通り。

FROM alpine:3.11
RUN apk update && apk add boost cmake make clang gcc \
  pkgconfig \
  linux-headers\
  python3\
  curl\
  ninja\
  tar\
  g++\
  python3-dev\
  musl\
  musl-dev

RUN pip3 install numpy

WORKDIR /tmp
RUN curl -sSL https://github.com/opencv/opencv/archive/4.2.0.tar.gz | tar xz
RUN mkdir build-opencv && cd build-opencv \
  cmake -G Ninja \
    -D CMAKE_BUILD_TYPE=Release\
    -D CMAKE_INSTALL_PREFIX=/usr/local\
    -D OPENCV_PYTHON3_VERSION=ON\   <----これを消せば問題なく動いた。。。
    -D BUILD_TESTS=OFF\
    ../opencv-4.2.0

このコードはミニマムなDockerfileでないので実運用上はpython3-devみたいなのはapk add時に--virtual-envを使って最後にpurgeするようにしたほうが良い。

それはさておき、このDockerfileをビルドするとcmakeに失敗してエラーがでる。

-- Found PythonInterp: /usr/bin/python2.7 (found suitable version "2.7.16", minimum required is "2.7")
-- Could NOT find PythonLibs (missing: PYTHON_LIBRARIES PYTHON_INCLUDE_DIRS) (Required is exact version "2.7.16")
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: No module named numpy.distutils
CMake Error at cmake/OpenCVUtils.cmake:131 (find_package):
  find_package called with invalid argument "ON"
Call Stack (most recent call first):
  cmake/OpenCVDetectPython.cmake:58 (find_host_package)
  cmake/OpenCVDetectPython.cmake:280 (find_python)
  CMakeLists.txt:585 (include)
-- Python is not found: ON EXACT

要約するとPythonインタプリタを探そうとすると2系が引っかかる。 また、Python3を見つけようとしない。 見つけようとしない原因はfind_package called with invalid argument "ON"にあって、謎の引数ONが与えられているところにある。

解決方法

cmakeのオプションに「-DOPENCV_PYTHON3_VERSION=3.8」を追加する

詳細

しかたがないのでソースコードを読む。 これまた面倒だが、エラーが出ているのは毎度おなじみOpenCVが中で書いているcmakeのコードだ。 OpenCV 2.X系をCygwinでビルドする時にFind~が死んでオコになった記憶があるので、あまり触りたくないのだが仕方がない。 ちなみに以下は280行目の呼び出し部分だ。

find_python("${OPENCV_PYTHON3_VERSION}" "${MIN_VER_PYTHON3}" PYTHON3_LIBRARY PYTHON3_INCLUDE_DIR
    PYTHON3INTERP_FOUND PYTHON3_EXECUTABLE PYTHON3_VERSION_STRING
    PYTHON3_VERSION_MAJOR PYTHON3_VERSION_MINOR PYTHON3LIBS_FOUND
    PYTHON3LIBS_VERSION_STRING PYTHON3_LIBRARIES PYTHON3_LIBRARY
    PYTHON3_DEBUG_LIBRARIES PYTHON3_LIBRARY_DEBUG PYTHON3_INCLUDE_PATH
    PYTHON3_INCLUDE_DIR PYTHON3_INCLUDE_DIR2 PYTHON3_PACKAGES_PATH
    PYTHON3_NUMPY_INCLUDE_DIRS PYTHON3_NUMPY_VERSION)

なるほど分からん。 が、ほとんどが変数名を渡している引数なので本質的に重要なのは第2引数までと一目で分かるので、とりあえずその2つをチェックする。

# Find specified Python version
# Arguments:
#   preferred_version (value): Version to check for first
#   min_version (value): Minimum supported version
#   library_env (value): Name of Python library ENV variable to check
#   include_dir_env (value): Name of Python include directory ENV variable to check
#   found (variable): Set if interpreter found
#   executable (variable): Output of executable found
#   version_string (variable): Output of found version
#   version_major (variable): Output of found major version
#   version_minor (variable): Output of found minor version
#   libs_found (variable): Set if libs found
#   libs_version_string (variable): Output of found libs version
#   libraries (variable): Output of found Python libraries
#   library (variable): Output of found Python library
#   debug_libraries (variable): Output of found Python debug libraries
#   debug_library (variable): Output of found Python debug library
#   include_path (variable): Output of found Python include path
#   include_dir (variable): Output of found Python include dir
#   include_dir2 (variable): Output of found Python include dir2
#   packages_path (variable): Output of found Python packages path
#   numpy_include_dirs (variable): Output of found Python Numpy include dirs
#   numpy_version (variable): Output of found Python Numpy version
function(find_python preferred_version min_version library_env include_dir_env
         found executable version_string version_major version_minor
         libs_found libs_version_string libraries library debug_libraries
         debug_library include_path include_dir include_dir2 packages_path
         numpy_include_dirs numpy_version)

つまるところ、第1引数が希望するバージョン、第2引数がミニマムなバージョンらしい。 しかもよく見ると、find_pythonの直上にoption(OPENCV_PYTHON3_VERSION "Python3 version" "") が存在するので、これを設定すれば良いことも自明であった。

悲しいかな。 ということで、cmakeに-D OPENCV_PYTHON3_VERSION=3.8で今回のケースは終了。 ソースコードを読むことが解決の最短ルートということでした。 数年に一度OpenCVのビルドに苦しめられるので、どなたかOpenCVDetectPythonでPythonを見つけられない原因について調べてpull reqしておいて貰えると助かります。