Python
OpenCV
Python3
cx_Freeze

cx_Freeze で依存ライブラリのコピー中にこける (Python3, OpenCV3)

More than 1 year has passed since last update.

概要

cx_Freeze 使って Python スクリプトを app にしていたら OpenCV の import に失敗していたので (暫定的な) 解決法をメモ.cx_Freeze の使い方とかはたくさんネットに上がっているのでこことか参照してください.

症状

環境:

  • MacOS: 10.12.6
  • Python: 3.5.2
  • OpenCV: 3.1.0 (余談ですが MacOS で Python3.6 だと OpenCV3 入らない問題いつ解決されるんですかね)

簡単のために cv2.imshow() するだけの main.py を作成.

main.py
import cv2

window_name = 'sample'
file_name = '/path/to/img'

img = cv2.imread(file_name)
cv2.imshow(window_name, img)

cv2.waitKey(5000)

cx_Freeze の build 用スクリプトはこんな感じで (ここから拝借).

setup.py
import sys
from cx_Freeze import setup, Executable

build_exe_options = {"packages": ["os", 'sys', 'cv2']}

base = None
if sys.platform == "win32":
    base = "Win32GUI"

setup(  name = "test",
        version = "0.0",
        description = "My GUI application!",
        options = {"build_exe": build_exe_options},
        executables = [Executable("main.py", base=base)])

build すると依存ライブラリのコピー中にこんなエラーが出ました.

$ python setup.py build
running build
running build_exe
...
copying mac64/libcilkrts.5.dylib -> build/exe.macosx-10.6-x86_64-3.5/libcilkrts.5.dylib
error: [Errno 2] No such file or directory: 'mac64/libcilkrts.5.dylib'

解法

他のライブラリはフルパスで指定しているのにこれだけ相対パスになってるからですね.brew で gcc 入れてるからかな〜とも思いましたけど普通に /usr/local/Cellar/gcc/ 以下も読み行ってるしよく分からないですが,cx_Freeze のバグではって感じです (このへん).

圧倒的に脳筋な解法なんですけど,要するに libcilkrts.5.dylib が見つからないだけなのでこれがあるところに mac64 って名前でシンボリックリンク貼ったら解決します.

$ find /usr/local/Cellar -name '*libcilkrts*'
/usr/local/Cellar/gcc/7.1.0/lib/gcc/7/libcilkrts.5.dylib

みたいに見つかると思うので,setup.py があるディレクトリで,

$ ln -s /usr/local/Cellar/gcc/7.1.0/lib/gcc/7/ mac64

するだけです.

これで build は通りますが,生成された main 実行すると実行時エラー吐きます.

ImportError: numpy.core.multiarray failed to import

OpenCV を使用するする際には numpy も packages に追加しましょう (Python で import cv2 するときはよしなにやってくれるんですがね).setup.py 中の

build_exe_options = {"packages": ["os", 'sys', 'cv2']}

を,

build_exe_options = {"packages": ["os", 'sys', 'numpy', 'cv2']}

とすれば無事描画できます.

以上です.cx_Freeze.setup() に /usr/local/Cellar/gcc/7.1.0/lib/gcc/7/ も読み行けよみたいなオプション与えられればそれで終わるんですけどよくわかりませんでした,どなたかご存知でしたら教えてください.