Kivy 1.9.1 Windows 包 .spec 单个 exe

Posted

技术标签:

【中文标题】Kivy 1.9.1 Windows 包 .spec 单个 exe【英文标题】:Kivy 1.9.1 Windows package .spec single exe 【发布时间】:2016-05-17 03:25:14 【问题描述】:

我想为我的应用制作一个 Windows 包,其中大多数文件都在 .exe 中。根据Kivy - Create package on Windows,我安装了 setuptools 19.2。我在 Kivy 1.9.1 稳定版上。

根据https://kivy.org/docs/guide/packaging-windows.html 上的说明,我得到了以下 working .spec 文件:

from kivy.deps import sdl2, glew
# -*- mode: python -*-

block_cipher = None


a = Analysis(['..\\foo\\main.py'],
             pathex=['path\\KO-exe'],
             binaries=None,
             datas=None,
             hiddenimports=['six','packaging','packaging.version','webbrowser'],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          exclude_binaries=True,
          name='foo',
          debug=False,
          strip=False,
          upx=True,
          console=True , icon='..\\foo\\ko.ico')
coll = COLLECT(exe, Tree('..\\foo\\'),
               a.binaries,
               a.zipfiles,
               a.datas,
               *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins )],
               strip=False,
               upx=True,
               name='foo')

但是,我最终得到一个包含许多文件的文件夹,而不是我可以分发给其他人的东西。因此,通过添加命令 --onefile 并将相同的步骤应用于 .spec 文件,我得到以下 NOT WORKING .spec:

# -*- mode: python -*-
from kivy.deps import sdl2, glew

block_cipher = None


a = Analysis(['..\\foo\\main.py'],
             pathex=['path\\KO-exe'],
             binaries=None,
             datas=None,
             hiddenimports=['six','packaging','packaging.version','webbrowser'],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz, Tree('..\\foo\\'),
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins )],
          name='foo',
          debug=False,
          strip=False,
          upx=True,
          console=True , icon='..\\foo\\ko.ico')

错误: .exe 仅在build 文件夹中而不在dist 中,运行时:Error loading Python DLL: C:\Users\user\AppData\Local\Temp\_MEI81162\python27.dll (error code 126)

问题

我一直在尝试将工作 .spec 和单个 .spec 进行各种组合(添加 COLLECT,移动 Tree('..\\foo\\')),但无济于事。

我应该改变什么才能拥有一个工作的单个 .exe? 如何选择要排除的文件/文件夹? (我应该在Tree() 中使用什么语法?) 除了 data\db\database.db(在 .exe 中太慢)之外,我想要 .exe 中的几乎所有内容。我该怎么做?

编辑 3

在@tito 的帮助下工作的 .spec 文件:

from kivy.deps import sdl2, glew
# -*- mode: python -*-
#import pdb
import sys

sys.path += ["..\\foo\\"]

block_cipher = pyi_crypto.PyiBlockCipher(key='1234567890')

#'six','packaging','packaging.version',
a = Analysis(['..\\foo\\main.py'],
             pathex=['D:\\path\\KO-exe'],
             binaries=None,
             datas=None,
             
             hiddenimports=[
             'webbrowser',
             '__init__',
             'data.__init__',
             'data.screens.__init__',
             'data.screens.dbmanager',
             'data.screens.db_kv.__init__',
             'data.screens.db_kv.backupsd',
             ],
             
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
             
#pdb.set_trace()
             
# exclusion list
from os.path import join
from fnmatch import fnmatch
exclusion_patterns = (
    join("kivy_install", "data", "images", "testpattern.png"),
    join("kivy_install", "data", "images", "image-loading.gif"),
    join("kivy_install", "data", "keyboards*"),
    join("kivy_install", "data", "settings_kivy.json"),
    join("kivy_install", "data", "logo*"),
    join("kivy_install", "data", "fonts", "DejaVuSans*"),
    join("kivy_install", "modules*"),
    join("Include*"),
    join("sdl2-config"),
    # Filter app directory
    join("personal*"),
    join("sign-apk*"),
    join(".idea*"),
)

def can_exclude(fn):
    for pat in exclusion_patterns:
        if fnmatch(fn, pat):
            return True
            
a.datas = [x for x in a.datas if not can_exclude(x[0])]
a.binaries = [x for x in a.binaries if not can_exclude(x[0])]
# Filter app directory
appfolder = [x for x in Tree('..\\foo\\', excludes=['*.py','*.pyc']) if not can_exclude(x[0])]  

#print(a.zipped_data)

#pdb.set_trace()
            
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)

exe = EXE(pyz,
          a.scripts,
          exclude_binaries=True,
          name='foo',
          debug=True,
          strip=False,
          upx=True,
          console=True , icon='..\\foo\\ko.ico')
coll = COLLECT(exe, appfolder,
               a.binaries,
               a.zipfiles,
               a.datas,
               *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins )],
               strip=False,
               upx=True,
               name='foo')

我想从我的应用程序文件夹中排除文件夹和文件,感谢tito,通过你我也想出了如何过滤Tree()

让 PyInstaller 排除文件后,我将尝试在输出文件上运行 NSIS。

【问题讨论】:

对于带有 NSIS 的单 exe:***.com/questions/35552659/… 【参考方案1】:

Imo,我不知道您的应用程序在 onefile 模式下失败的确切原因。但是由于在 pyinstaller 中使用 onefile 模式的含义(它会在每次运行时将文件解压缩到一个临时目录中),使用NSIS 进行安装可能会更好。

要选择要排除的模块,您可以将它们放在Analysisexcludes 参数中:

excludes=["pickle", "csv"]

为了排除文件,我通常在分析之后/EXE 之前进行手动排除。这是一个例子:

# exclusion list
from fnmatch import fnmatch
exclusion_patterns = (
    join("kivy_install", "data", "images", "testpattern.png"),
    join("kivy_install", "data", "images", "image-loading.gif"),
    join("kivy_install", "data", "keyboards*"),
    join("kivy_install", "data", "settings_kivy.json"),
    join("kivy_install", "data", "logo*"),
    join("kivy_install", "data", "fonts", "DejaVuSans*"),
    join("kivy_install", "modules*"),
    join("Include*"),
    join("sdl2-config"),
)

def can_exclude(fn):
    for pat in exclusion_patterns:
        if fnmatch(fn, pat):
            return True
a.datas = [x for x in a.datas if not can_exclude(x[0])]
a.binaries = [x for x in a.binaries if not can_exclude(x[0])]

【讨论】:

当我在 Exe() 之前重新分配它时,您直接在 Collect() 中使用了 a.binaries。如果您想直接在 Collect() 规则中使用它,请使用“binaries=...”,而不是“a.binaries=...” 我认为a.datas的位置只是为了空间方便。我还想过滤 Tree() ,多亏了你,我成功了,请参阅更新的答案。现在我可以继续尝试 NSIS。

以上是关于Kivy 1.9.1 Windows 包 .spec 单个 exe的主要内容,如果未能解决你的问题,请参考以下文章

Kivy 1.9.0 Windows 包 KeyError: 'rthooks'

kivy 有没有windows64位安装包

从 OSX 为 Windows 创建 Kivy 包

在 centos 7 上使用 SDL2 运行 kivy 1.9.1

如何让 Kivy 1.9.1 或 1.9.2 在 OSX 10.12.2 上使用 SDL2 而不是 pygame?

Kivy,Python:我无法减小 PyInstaller 生成的包的大小