cx_Freeze - 防止包含不需要的包

时间:2014-12-03 20:48:12

标签: python deployment pyqt cx-freeze

我使用PyQt4编写了一个很小的python程序。现在,我想使用cx_Freeze创建一个独立的应用程序。一切正常 - cx_Freeze自动包含所有必要的模块;由此产生的exe工作。

唯一的问题是cx_Freeze将大量不需要的模块打包到独立模块中。即使我只使用QtCore和QtGui,也包括sqlite3,QtNetwork或QtScript等模块。令人惊讶的是,我在结果文件夹中找到了PyQt5 dll。在我看来,好像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"]}

具有相同的结果。

除了无聊的Qt包之外,我还找到了名为“imageformats”,“tcl”和“tk”的不需要的文件夹。如何保留所需文件,以使独立文件夹和安装程序尽可能小?

我用谷歌搜索了这个问题好几个小时但只发现了this thread并没有帮助我。

我正在Windows 8上运行python 3.4.2 amd64。

我很高兴能够以合理的尺寸“独立”地提供所需结果的每个解决方案。我也尝试了pyqtdeploy,但遇到了错误:QT中的未知模块(但这是一个不同的问题)。

编辑:

我正在使用两个模块。一个是由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 *

也许这有助于找出问题所在。

3 个答案:

答案 0 :(得分:12)

无效“排除”命令的原因是我忘记将构建选项包含在设置中。将相应的行添加到代码中不包括作品:

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}

我会为更优雅的解决方案感到高兴。仍然欢迎进一步的想法。不过,我认为这个问题已经解决了。

答案 1 :(得分:1)

对于一个小型数据库,我在一个非常简单的PyQt4 Gui上遇到了类似的问题,该程序的少量代码程序为58Mb,问题是程序中包括了整个PyQt4文件夹。

文章here涉及在您的选项中使用zip_include_packages排除文件或压缩它们以减小文件大小。

我排除了整个PyQt4文件夹,然后包括了我需要的位,如下所示,它自动将整个程序包减少到16Mb

options = {
'build_exe': {
    'packages':packages,
    'zip_include_packages':'PyQt4',
    'includes':['PyQt4.QtCore','PyQt4.QtGui','sqlite3','sys','os'],
},

不确定这样做是正确的方法,但到目前为止似乎尚未对我的程序产生负面影响

答案 2 :(得分:0)

这是我将可执行文件优化到最小文件大小的方式

from cx_Freeze import setup, Executable
import subprocess
import sys


NAME = 'EXE NAME'
VERSION = '1.0'
PACKAGES = ['pygame']
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:
    EXCLUDES.remove(pkg)


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': PACKAGES,
                           'include_files': ['FOLDER'],
                           'excludes': EXCLUDES,
                           'optimize': 2}},
    executables=executables)