PyQt4を使用して小さなpythonプログラムをコーディングしました。次に、cx_Freezeを使用してスタンドアロンアプリケーションを作成します。すべてが正常に機能します。cx_Freezeには必要なすべてのモジュールが自動的に含まれ、結果のexeが機能します。
唯一の問題は、cx_Freezeが不要なモジュールをスタンドアロンにパックすることです。 QtCoreとQtGuiのみを使用していますが、sqlite3、QtNetwork、QtScriptなどのモジュールも含まれています。驚いたことに、結果のフォルダーにPyQt5dllも見つかりました。 cx_FreezeがインストールしたすべてのPyQtパッケージを使用しているように見えます。結果は200Mbのプログラムです-私は小さなスクリプトしか書いていませんが。
どうすればこの動作を防ぐことができますか?
次のsetup.pyを使用します。
import sys
from cx_Freeze import setup, Executable
setup(
name="MyProgram",
version="0.1",
description="MyDescription",
executables=[Executable("MyProgram.py", base = "Win32GUI")],
)
次のコードを追加して、一部のパッケージを明示的に除外しようとしました(ただし、未使用のQtモジュールをすべて除外するのは非常に面倒です)。
build_exe_options = {"excludes": ["tkinter", "PyQt4.sqlite3",
"PyQt4.QtOpenGL4", "PyQt4.QtSql"]}
しかし、上のモジュールはまだ使用されていました。私も試しました
build_exe_options = {"excludes": ["tkinter", "PyQt4.sqlite3",
"QtOpenGL4", "QtSql"]}
同じ結果になります。
Nedless Qtパッケージに加えて、「imageformats」、「tcl」、「tk」などの名前のunnededフォルダーもあります。スタンドアロンフォルダーとインストーラーをできるだけ小さくするために、only必要なファイルを含めるにはどうすればよいですか?
私はこの問題を何時間もグーグルで検索しましたが、 このスレッド しか見つかりませんでした。
私はWindows8でpython 3.4.2AMD64を実行しています。
妥当なサイズで「スタンドアロン」の望ましい結果が得られるすべてのソリューションに満足しています。 pyqtdeployも試しましたが、エラーが発生しました:QTの不明なモジュール(ただし、これは別の質問です)。
私は2つのモジュールを使用しています。 1つは、uicによって作成されたGUIクラス「MyProgramGUIPreset」です。このファイルには、次のインポートコマンドがあります。
from PyQt4 import QtCore, QtGui
from matplotlibwidget import MatplotlibWidget
メインモジュールでは、次のインポートを行います。
import MyProgramGUIPreset
import numpy as np
from PyQt4.QtGui import QApplication, QMainWindow, QMessageBox
import sys
from math import *
たぶん、これは問題がどこにあるかを理解するのに役立ちます。
「excludes」コマンドが機能しない理由は、ビルドオプションをセットアップに含めるのを忘れたためです。作品を除くコードにそれぞれの行を追加した後:
from cx_Freeze import setup, Executable
import sys
# exclude unneeded packages. More could be added. Has to be changed for
# other programs.
build_exe_options = {"excludes": ["tkinter", "PyQt4.QtSql", "sqlite3",
"scipy.lib.lapack.flapack",
"PyQt4.QtNetwork",
"PyQt4.QtScript",
"numpy.core._dotblas",
"PyQt5"],
"optimize": 2}
# Information about the program and build command. Has to be adjusted for
# other programs
setup(
name="MyProgram", # Name of the program
version="0.1", # Version number
description="MyDescription", # Description
options = {"build_exe": build_exe_options}, # <-- the missing line
executables=[Executable("MyProgram.py", # Executable python file
base = ("Win32GUI" if sys.platform == "win32"
else None))],
)
これにより、プログラムサイズが230MBから120MBに減少しました。それにもかかわらず、私はすべての不要なパッケージを除外する良い方法を見つけられませんでした。試行錯誤(ビルドフォルダー内の最大のファイルをテスト的に削除)によって、除外できるクラスを見つけました。
Matplotlibバックエンドが問題を引き起こすかどうかを試しましたが、最終的にはそうではないことがわかりました。それでも、特定のフォルダ内の特定の名前スキームのすべてのモジュールを除外するコードが必要な場合は、特別なものを除いて、次のことを自分のニーズに合わせて調整できます。
mplBackendsPath = os.path.join(os.path.split(sys.executable)[0],
"Lib/site-packages/matplotlib/backends/backend_*")
fileList = glob.glob(mplBackendsPath)
moduleList = []
for mod in fileList:
modules = os.path.splitext(os.path.basename(mod))[0]
if not module == "backend_qt4agg":
moduleList.append("matplotlib.backends." + modules)
build_exe_options = {"excludes": ["tkinter"] + moduleList, "optimize": 2}
もっとエレガントなソリューションがあれば嬉しいです。さらなるアイデアはまだ歓迎されています。それにもかかわらず、私は問題が私のために解決されたと思います。
プログラムが少量のコードで58Mbである、小さなデータベースの非常に単純なPyQt4 Guiでも同様の問題が発生していました。問題は、PyQt4フォルダー全体がプログラムに含まれていることです。
記事 ここ は、オプションでZip_include_packagesを使用してファイルを除外するか、ファイルを圧縮してファイルサイズを縮小することについて言及しています。
PyQt4フォルダー全体を除外してから、以下に示すように必要なビットを含めると、パッケージ全体が自動的に16Mbに削減されました。
options = {
'build_exe': {
'packages':packages,
'Zip_include_packages':'PyQt4',
'includes':['PyQt4.QtCore','PyQt4.QtGui','sqlite3','sys','os'],
},
それが正しい方法かどうかはわかりませんが、現時点では私のプログラムに悪影響はないようです
これが、実行可能ファイルを最小ファイルサイズに最適化した方法です。
from cx_Freeze import setup, Executable
import subprocess
import sys
NAME = 'EXE NAME'
VERSION = '1.0'
PACKAGES = ['pygame', ('import_name', 'package_name')]
# if names are same just have a string not a Tuple
installed_packages = subprocess.check_output([sys.executable, '-m', 'pip', 'freeze']).decode('utf-8')
installed_packages = installed_packages.split('\r\n')
EXCLUDES = {pkg.split('==')[0] for pkg in installed_packages if pkg != ''}
EXCLUDES.add('tkinter')
for pkg in PACKAGES:
if type(pkg) == str: EXCLUDES.remove(pkg)
else: EXCLUDES.remove(pkg[1])
executables = [Executable('main.py', base='Win32GUI', icon='Resources/Jungle Climb Icon.ico', targetName=NAME)]
setup(
name=NAME,
version=VERSION,
description=f'{NAME} Copyright 2019 AUTHOR',
options={'build_exe': {'packages': [pkg for pkg in PACKAGES if type(pkg) == str else pkg[0]],
'include_files': ['FOLDER'],
'excludes': EXCLUDES,
'optimize': 2}},
executables=executables)