この記事は何?
pyenv環境下でOpenCVを野良ビルドしようとしてcmake
を実行した際に,
--
-- Python 2:
-- Interpreter: /home/username/.pyenv/shims/python2.7 (ver 2.7.14)
--
-- Python 3:
-- Interpreter: /usr/bin/python3.4 (ver 3.4.3)
--
-- Python (for build): /home/username/.pyenv/shims/python2.7
--
などと表示されて,make
してもOpenCVのPython bindings (cv2.so
など) がビルドされない問題への対処方法.
方法
libpython*.so
の準備
通常,pyenvでPythonを入れるとstatic library (libpython*.a
) が導入される.
しかし,static libraryではOpenCVのビルド時に参照できない.
そこで,pyenvでPython環境をインストールする際にshared libraryを導入する.
pyenv install
の際に,以下のように環境変数を設定してからインストールを行う.
$ CONFIGURE_OPTS="--enable-shared" pyenv install <version_to_install>
libpython*.so
が導入されているかどうかは,pyenvのインストールディレクトリ以下を見ることで確認できる.
$ ls $(pyenv root)/versions/3.6.3/lib/
libpython3.6m.so libpython3.6m.so.1.0 libpython3.so pkgconfig python3.6
$ ls $(pyenv root)/versions/2.7.14/lib/
libpython2.7.so libpython2.7.so.1.0 pkgconfig python2.7
Pythonを入れた後に各バージョンに切り替えてnumpyも入れておく.
cmake
時のパス設定
運が良ければ,上記の設定をした後にcmake
をすれば正しくPython bindingsのビルド設定が行われる.
しかし,私の環境ではビルド設定が正しく行われなかったため,以下のオプションをcmake
時に追加した.
OpenCVのバージョンは3.4.4
と4.0.0
,Pythonのバージョンは2.7.15
と3.6.7
で確認しています.
$ PYTHON3_VERSION="3.6.7"
$ PYTHON2_VERSION="2.7.15"
$ rm CMakeCache.txt
$ cmake .. \
-Dbuild_opencv_python3=YES -Dbuild_opencv_python2=YES \
-DPYTHON3_EXECUTABLE="$(pyenv global $PYTHON3_VERSION; pyenv which python)" \
-DPYTHON3_INCLUDE_DIR="$(pyenv global $PYTHON3_VERSION; python -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())")" \
-DPYTHON3_NUMPY_INCLUDE_DIRS="$(pyenv global $PYTHON3_VERSION; python -c "import os, numpy.distutils; print(os.pathsep.join(numpy.distutils.misc_util.get_numpy_include_dirs()))")" \
-DPYTHON3_LIBRARY="$(pyenv global $PYTHON3_VERSION; python -c "import distutils.sysconfig as sysconfig; print(sysconfig.get_config_var('LIBDIR') + '/' + sysconfig.get_config_var('LDLIBRARY'))")" \
-DPYTHON2_EXECUTABLE="$(pyenv global $PYTHON2_VERSION; pyenv which python)" \
-DPYTHON2_INCLUDE_DIR="$(pyenv global $PYTHON2_VERSION; python -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())")" \
-DPYTHON2_NUMPY_INCLUDE_DIRS="$(pyenv global $PYTHON2_VERSION; python -c "import os, numpy.distutils; print(os.pathsep.join(numpy.distutils.misc_util.get_numpy_include_dirs()))")" \
-DPYTHON2_LIBRARY="$(pyenv global $PYTHON2_VERSION; python -c "import distutils.sysconfig as sysconfig; print(sysconfig.get_config_var('LIBDIR') + '/' + sysconfig.get_config_var('LDLIBRARY'))")"
これらのオプションを指定しておくと,cmake
時のビルド設定が正しく行われる.
(正しく設定されない場合は,キャッシュCMakeCache.txt
を消してからもう一度.)
--
-- Python 2:
-- Interpreter: /home/username/.pyenv/versions/2.7.15/bin/python (ver 2.7.14)
-- Libraries: /home/username/.pyenv/versions/2.7.15/lib/libpython2.7.so (ver 2.7.14)
-- numpy: /home/username/.pyenv/versions/2.7.15/lib/python2.7/site-packages/numpy/core/include (ver 1.13.3)
-- packages path: lib/python2.7/site-packages
--
-- Python 3:
-- Interpreter: /home/username/.pyenv/versions/3.6.7/bin/python (ver 3.6.3)
-- Libraries: /home/username/.pyenv/versions/3.6.7/lib/libpython3.6m.so (ver 3.6.3)
-- numpy: /home/username/.pyenv/versions/3.6.7/lib/python3.6/site-packages/numpy/core/include (ver 1.14.2)
-- packages path: lib/python3.6/site-packages
--
-- Python (for build): /home/username/.pyenv/versions/2.7.15/bin/python
--
よくわかる解説
PYTHON3_EXECUTABLE
, PYTHON2_EXECUTABLE
このオプションには,Pythonインタプリタのパスを設定すれば良い.
しかし,pyenv環境ではsym link (~/.pyenv/shims/python
) がPythonインタプリタとしてデフォルトで検出されるようで,インクルードディレクトリやライブラリとの整合性が取れなくなる場合がある.
そこで,Pythonインタプリタのリンク元のパスをオプションで指定する.
コマンドの実行結果は以下のようになる.
$ echo "$(pyenv global 3.6.7; pyenv which python)"
/home/username/.pyenv/versions/3.6.3/bin/python
$ echo "$(pyenv global 2.7.15; pyenv which python)"
/home/username/.pyenv/versions/2.7.14/bin/python
PYTHON3_INCLUDE_DIR
, PYTHON2_INCLUDE_DIR
このオプションには,Pythonのインクルードパスを指定する.
何も設定せずにcmake
した場合,システムのPythonのインクルードパスを検知することが多い模様である.
コマンドの実行結果は以下のようになる.
$ echo "$(pyenv global 3.6.7; python -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())")"
/home/username/.pyenv/versions/3.6.3/include/python3.6m
$ echo "$(pyenv global 2.7.15; python -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())")"
/home/username/.pyenv/versions/2.7.14/include/python2.7
PYTHON3_NUMPY_INCLUDE_DIRS
, PYTHON2_NUMPY_INCLUDE_DIRS
このオプションには,numpyのインクルードパスを指定する.
何も設定せずにcmake
した場合,システムのPythonにインストールされているnumpyのインクルードパスを検知することが多い模様である.
コマンドの実行結果は以下のようになる.
$ echo "$(pyenv global 3.6.7; python -c "import os, numpy.distutils; print(os.pathsep.join(numpy.distutils.misc_util.get_numpy_include_dirs()))")"
/home/username/.pyenv/versions/3.6.3/lib/python3.6/site-packages/numpy/core/include
$ echo "$(pyenv global 2.7.15; python -c "import os, numpy.distutils; print(os.pathsep.join(numpy.distutils.misc_util.get_numpy_include_dirs()))")"
/home/username/.pyenv/versions/2.7.14/lib/python2.7/site-packages/numpy/core/include
PYTHON3_LIBRARY
, PYTHON2_LIBRARY
このオプションには,Pythonのshared libraryのパスを指定する.
何も設定せずにcmake
した場合,システムのPythonのshared libraryを検知することが多い模様である.
また,pyenvでPython環境を用意した際にlibpython*.so
が導入されていないと,ここで詰む.
コマンドの実行結果は以下のようになる.
$ echo "$(pyenv global 3.6.7; python -c "import distutils.sysconfig as sysconfig; print(sysconfig.get_config_var('LIBDIR') + '/' + sysconfig.get_config_var('LDLIBRARY'))")"
/home/username/.pyenv/versions/3.6.3/lib/libpython3.6m.so
$ echo "$(pyenv global 2.7.15; python -c "import distutils.sysconfig as sysconfig; print(sysconfig.get_config_var('LIBDIR') + '/' + sysconfig.get_config_var('LDLIBRARY'))")"
/home/username/.pyenv/versions/2.7.14/lib/libpython2.7.so
PYTHONPATH
の設定
OpenCVのモジュールパスを環境変数PYTHONPATH
に登録する.
OpenCVのインクルードパスに依存するが,例えば~/usr
以下にインストールしている (=CMAKE_PREFIX_PATH
を$HOME/usr
に設定した) 場合には,
$ ls ~/usr/lib/python2.7/site-packages/
cv2.so
$ ls ~/usr/lib/python3.6/site-packages/
cv2.cpython-36m-x86_64-linux-gnu.so
といった場所にモジュールが配置されている.これらをPYTHONPATH
に登録する.
Python2系であれば
export PYTHONPATH="$HOME/usr/lib/python2.7/site-packages:$PYTHONPATH"
Python3系であれば
export PYTHONPATH="$HOME/usr/lib/python3.6/site-packages:$PYTHONPATH"
を~/.profile
等に記述する.
(間違ったバージョンのパスが登録されているとimport
時にエラーを吐く.)
もし,Pythonのバージョンに応じて動的にPYTHONPATH
を変更したい場合は,
PYTHON_MAJOR_VERSION=$(python -c "import sys; print(sys.version_info.major)")
if [ $PYTHON_MAJOR_VERSION = "3" ]; then
export PYTHONPATH="$HOME/usr/lib/python3.6/site-packages:$PYTHONPATH"
elif [ $PYTHON_MAJOR_VERSION = "2" ]; then
export PYTHONPATH="$HOME/usr/lib/python2.7/site-packages:$PYTHONPATH"
fi
のように書いておく.
終わりに
OpenCVをビルドするのが日課になってきた.