python py2exeでexe化した後、pyside周りとかでエラーがでた場合の対処のメモ


最近は、ちょっとしたアプリをお手軽なVCではなくpythonで作っている。
pythonでexeを作る場合に使うモジュールが、pyinstall か py2exe。
たしか、記憶では何年か前までpy2exeはpython2.7系でしか使えなかったが、最近はpython3.7以降でも使える。
ちなみに、pyinstallは簡単にexe化できるのだけれど、出来たexeの起動が遅かったり、データが重かったりと、ちょっとした使いづらさがあるので個人的にはexe化するならpy2exe一択。
pyinstall や py2exeでのexe化関連の記事は調べれば大量に出てくるので、そこは他人にお任せするとして、

困ったのはexe化したあとで動かなかった場合。

今まで幾つか経験していて、大半はpySide2 (pyQt)周りでのImport Errorが結構多かったと思う。
要するにpy2exeが必要なDLLなどをコピーしきれずに起動しなかったりエラーが起きるパターンが多いって感じかな?

exe化した後で動かなかった場合は自分で地道にエラー内容からデバッグしたりするのだけど、なかなか分らずスタックすることがしばしば。
ここ数日もエラーでなぜか動かず、ずーっと困っていたw、

つかオレ、デバッグへたくそすぎだろw

で、ネットでエラー内容を調べても、なかなか原因を解説しているサイトは少ない。
というか、ほとんどない。
もしかしたらVisualStudioでpythonのexe作ったほうがデバッグいいのかな・・・。

まぁ、なので、今まで経験したエラーと対処法を少しだけメモしておく。
たぶん役に立つ・・・はず。

エラー例1、PySide2とshiboken2のバージョンが違っていた

単純に使っていた、pySide2 と shiboken2 のバージョンが食い違っていたことが原因だった。
なので、対処法はpipを使って両方ともにバージョンアップする。
pipはこんな感じで。

C:\Users\<UserName>\AppData\Local\Programs\Python\Python37\python.exe -m pip install –upgrade PySide2
C:\Users\<UserName>\AppData\Local\Programs\Python\Python37\python.exe -m pip install –upgrade shiboken2

流石にpipの説明は必要なかったかw
ついでにpipとかpy2exeもバージョンアップしておくといいかも。

エラー例2、setup.pyの設定

エラーというよりもpy2exeに必要なsetup.pyの設定でモジュールを含める設定になってないとpyside2周りのモジュールが一切コピーされずエラーが起きる。

個人的なレシピは、必要ファイルをまとめつつzipで圧縮する方法
こんな感じ。

まぁ、あくまで参考程度で!

# -*- coding: utf-8 -*-
from distutils.core import setup
import py2exe


option = {
    "compressed": 1,
    "optimize": 2,
    "bundle_files": 3
}

include_data = [
    # ('フォルダ名', ['コピーファイル 相対パス'])
    ('images', [
        "images/icon.png",
        "images/checkbox_checked.png",
        "images/checkbox_checked_disabled.png",
        "images/checkbox_unchecked.png",
        "images/checkbox_unchecked_hover.png",
        "images/x.png",
        "images/remove.png",
        "images/filebrowser.png"]),
    ('platforms', ["platforms/qwindows.dll"]),
    ('styles', ["styles/qwindowsvistastyle.dll"]),
    ('', ["ffprobe.exe", "ffmpeg.exe", "style.qss"])
    ]

setup(
    options={
        "py2exe": option
    },
    windows=[{
        "script": "sj_video_conv.py",
        "icon_resources": [
            (1, "icon.ico")
            ],
        "name": "SJ Video Conv",
        "version": "1.0.8.0",
        "description": "",
        "company_name": "",
        "url": "http://"
    }],
    data_files=include_data,
    zipfile="lib\\libs.zip"
)

この方法で今のところさほど困ってはいない。
実はpyinstall並みにファイル容量が重くなってしまうんだけど、
不足ファイルがでてインポートエラーがあった場合、調べるのがメンドクサイのでこの方法でやってる。

エラー例3、パスが通ってない

これは、shotgun のAPIを利用した際にshotgunapiの中でcacerts.txtまでのパスが通ってなかったことが原因だった。
具体的には__ini__.pyの以下の場所。

CA_CERTS = os.path.join(os.path.dirname(os.path.abspath(__file__ )), "cacerts.txt")

この状態でexe化するとos.path.abspath(__file__)の部分が、.zip内のパスとして扱われるのでパスが通らない。
ここを

base = os.path.dirname(os.path.abspath(__file__)).split("\\")
base = base[0 : len(base) - 4]
CA_CERTS = os.path.join("\\".join(base), 'cacerts.txt')

こんな感じで無理やりzipの上の階層にさかのぼって参照するようにした。
書き方はもっといい方法があるはずw
もしくはzipにファイルを含ませるのもありかも。

実はこの手のちょっとしたパス切れってたまにあって、ちょくちょく手で直すようにしてるw
まぁ、こういう事例もあるよって覚えておくといいかも。
特にos.path.abspath(__file__)が出てきたら、ちょっと注意かな。

エラー例4、msvcp90.dllが無くて動かない

これはpython2.7系だったときに経験したエラーなんだけど、
どうもmsvcp90.dllというランタイムが無く動かなかった場合があった。
このDLLは名前からしてVC++関連のランタイムか何かだと思われる。
これも前述通りでpy2exeが必要なdllをコピーしきれていないってことだと思う。

対処方は、単純に msvcp90.dll をdistディレクトリにコピーする。
msvcp90.dll自体は Microsoft Visual C++のランタイムを入っている環境であれば検索すれば出てくる(はず)
対処したのが何年か前で詳細を覚えてないやw

エラー例5、必要なPySide2関連のDLLが無い。

まずこちらのエラー。

This application failed to start becase no Qt platform plugin
could be initialized. Reinstalling the application may fix this
problem.

文字通りで、プラグインの初期化に失敗してエラーがでているのだが、
原因は qwindows.dll (windowsの場合) と qwindowsvistastyle.dll が不足していたこと。
この2つのDLLは、PySide2のモジュールディレクトリ内にある。
モジュールディレクトリは、

C:\Users\<ユーザー名>\AppData\Local\Programs\Python\Python37\Lib\site-packages\PySide2

に入っているので検索すると出てくる。
このDLLをビルドするときにdistコピーする。
qwindows.dllとqwindowsvistastyle.dllをsetupと同階層などにコピーしておいて、
setup.py内で

include_data = [
    # ('フォルダ名', ['コピーファイル 相対パス'])
    ('platforms', ["platforms/qwindows.dll"]),
    ('styles', ["styles/qwindowsvistastyle.dll"])
    ]

みたいな感じで書いておくと便利。

つぎ、

最近起きたエラーで、vcruntime140_1.dll というVCのランタイムが無かったエラー。

これ厄介だったのが、出る環境と出ない環境があったこと。
おそらくVCのランタイムが何かのタイミングでインストールされた環境と無い環境の差が出てるんだと思う。

エラー文は以下のような感じ。

PySide2/init.py: Unable to import shiboken2 from C:\Users\<UserName>\Desktop\dist\lib\libs.zip
Traceback (most recent call last):
File “sim_job.py”, line 5, in
File “main.pyc”, line 14, in
File “sim_job_ui.pyc”, line 11, in
File “PySide2__init__.pyc”, line 120, in
File “PySide2__init__.pyc”, line 70, in setupQtDirectories File “shiboken2__init_.pyc”, line 27, in
File “”, line 10, in
File “”, line 8, in __load
ImportError: (DLL load failed: 指定されたモジュールが見つかりません。) ‘C:\Users\<UserName>\Desktop\dist\lib\shiboken2.shiboken2.pyd’

実はこれ、何のDLLが不足しているのか、所見ではまったくわからず、
必要そうなDLLを手あたり次第コピーしてようやく不足していたものを特定した。

vcruntime140_1.dll はPySide2モジュールディレクトリ内にあるので検索すれば出てくる。
他にもVCのランタイムがあるので、もしかしたら環境によっては不足しているDLLが違うかもしれない。
わからなかったら、とりあえず必要そうなDLL全部コピーで!!

なぜ、必要なDLLがコピーされないのか?って考えると、py2exeが単純に必要なDLLやファイルを拾え切れてないんだと思う。必要なものは自分でコピーしろってことなんだろうな。

という感じっす!!
以上pythonのpy2exeでexe化した後、pyside周りとかでエラーがでた場合の対処のメモでした!!

まぁ何かの参考になればいいかな~~。



Leave a comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください