PyInstallerでexe化したときにscipyでDLL load failed while importing _uarrayで落ちるのを解決した顛末の巻
はじめに
情報が少なかったので右往左往しまくりました。
exe化はできたのですが、scipyのimportのところでコケて落ちる。
File "scipy\_lib\_uarray\_backend.py", line 5, in <module>
ImportError: DLL load failed while importing _uarray: ダイナミック リンク ライブラリ (DLL) 初期化ルーチンの実行に失敗しました。
で、結局はPyInstallerのオプションで、
--collect-all "scipy"
としたらで解決できましたよ、と。
*ごめんなさいタイポがありました。。。「”scipy2」になってました。正しくは「”scipy”」です。。。修正しました(2022年6月16日)。
顛末
Pythonで作ったプログラムをPyInstallerでexe化して起動するところまで辿り着いたのですが、
scipy(ver. 1.8.0)のimportが絡む動作をしたときに、
ModuleNotFoundError: No module named 'scipy._lib._uarray._backend'
が出て落ちてしまいました。
なので問題解決につながりそうな、
https://stackoverflow.com/questions/51267453/scipy-import-error-with-pyinstaller
を参考に
PyInstallerがインストールされているディレクトリ配下のにある
\PyInstaller\hooks\
の
hook-scipy.py
にいくつかの追加の記載を試した(”#####追加” の部分)ところ、
import glob
import os
from PyInstaller.compat import is_win
from PyInstaller.utils.hooks import get_module_file_attribute
from PyInstaller.utils.hooks import collect_submodules ##### 追加
from PyInstaller.utils.hooks import collect_data_files ##### 追加
binaries = []
datas = collect_data_files('scipy') ##### 追加
# Package the DLL bundle that official scipy wheels for Windows ship The DLL bundle will either be in extra-dll on
# windows proper and in .libs if installed on a virtualenv created from MinGW (Git-Bash for example)
if is_win:
extra_dll_locations = ['extra-dll', '.libs']
for location in extra_dll_locations:
dll_glob = os.path.join(os.path.dirname(get_module_file_attribute('scipy')), location, "*.dll")
if glob.glob(dll_glob):
binaries.append((dll_glob, "."))
# collect library-wide utility extension modules
hiddenimports = ['scipy._lib.%s' % m for m in ['messagestream', "_ccallback_c", "_fpumode"]]
hiddenimports += collect_submodules('scipy') ##### 追加
さっきのエラーは出なくなったのですが、
今度は
File "scipy\_lib\_uarray\_backend.py", line 5, in <module>
ImportError: DLL load failed while importing _uarray: ダイナミック リンク ライブラリ (DLL) 初期化ルーチンの実行に失敗しました。
と言われる様になってしまいました。
イベントビューアーからエラーログを見ると、
例外コード: 0xc0000005
というわけでsegmentation fault(メモリアクセス違反)が出ているのでした。
うーんなんでか全然わからん。
で、その後はPyInstallerの.specファイルのhidden importのところをいじってみたのですがうまくいかず、
他にもscipyのソースをいじってみたり、mkl入りのnumpyを入れてみたり、numpyやscipyのバージョン変えたり、「これかも」ということをいろいろ試しましたが、どれも解決には至りませんでした。うう、知識が足らぬ。
で、結局は
https://stackoverflow.com/questions/69651559/dll-load-failed-while-importing-defs
に記載のあった、
--collect-all "scipy"
を追加することでうまくいったのでした。scipyのバージョンは1.8.0です。
PyInstalleの実行コマンド例としては次の様になります。
python -m PyInstaller --onefile --collect-all "scipy" XXXXX.py
注1;実際はもっと色々オプションを追加しているのですが、簡単のため省略しています。
注2;XXXXXはpyファイル名です。
注3;hook-scipy.pyは変更したままなので、–collect-all “scipy”の追加だけで解決するのかは未確認です。
いやーありがとうございます。
具体的に何がどううまくいっていなかったのか、なぜうまくいったのかが未だに掴めていませんが、まあとりあえず、めでたしめでたし。
実施環境
*pyenvを使って、pipenvでの仮想環境下で実施しています。
MacBook 2017 (Intel Core m3, 1.2 GHz, RAM 8GB)(Boot CampでWindows10を導入)
Windows10 Home 21H2
PowerShell version; 5.1.19041.1682
Python 3.9.12
pyenv; 2.64.11
pipenv; version 2022.4.21
PyInstaller; 5.1
scipy; 1.8.0
numpy; 1.22.4
参考にした主なサイト
https://stackoverflow.com/questions/51267453/scipy-import-error-with-pyinstaller
https://stackoverflow.com/questions/69651559/dll-load-failed-while-importing-defs