【问题标题】:PyInstaller Packages for kivykivy 的 PyInstaller 软件包
【发布时间】:2014-06-26 09:13:54
【问题描述】:

我最近尝试使用PyInstaller 从我的kivy 应用程序中构建一个包。我的目标是创建一个可以在我的 Linux(Ubuntu 14.04 64 位)上执行的包,并将其复制到其他 Linux 系统。

我整晚都在尝试正确执行 PyInstaller,尝试了各种方法,最终成功为我自己的系统创建了一个包。首先,我想知道我究竟做了什么来功能性地打包我的应用程序。

我的main.spec 文件如下所示:

# Part A
from kivy.tools.packaging.pyinstaller_hooks import install_hooks
install_hooks(globals())
# -*- mode: python -*-

# Part B
from PyInstaller.hooks.hookutils import exec_statement
hiddenimports = ['pysqlite2', 'MySQLdb', 'psycopg2']
databases = exec_statement("import sqlalchemy.databases;
print sqlalchemy.databases.__all__")
databases = eval(databases.strip())
for n in databases:
    hiddenimports.append("sqlalchemy.databases." + n)
version = exec_statement('import sqlalchemy; print sqlalchemy.__version__')
is_alch06 = version >= '0.6'

if is_alch06:
    dialects = exec_statement("import sqlalchemy.dialects; print sqlalchemy.dialects.__all__")
    dialects = eval(dialects.strip())

    for n in databases:
        hiddenimports.append("sqlalchemy.dialects." + n)

block_cipher = None

# Part C
a = Analysis(['main.py'],
         pathex=['/home/grafgustav/Python/ICCHP/accessmail/src','/'],
         hiddenimports=[],
         cipher=block_cipher)
pyz = PYZ(a.pure,
         cipher=block_cipher)
exe = EXE(pyz,
      a.scripts,
      exclude_binaries=True,
      name='main',
      debug=False,
      strip=None,
      upx=True,
      console=True )


coll = COLLECT(exe, Tree("/home/grafgustav/Python/ICCHP/accessmail"),
           a.binaries, #...,
           a.zipfiles,
           a.datas,
           strip=None,
           upx=True,
           name='main',
           )

虽然我理解为什么 B 部分主要是多余的(我只是从 Internet 的某个地方复制了该部分)并且 A 部分获得了一些用于 kivy 的已完成挂钩,但我不太明白为什么这不会将整个应用程序打包为我愿意。

据我了解,钩子用于包含不直接导入的库,而是隐式导入或在运行时导入的库。就像隐藏进口一样。

主要问题是我生成的包中缺少的部分。在我的整个 src 目录中有一个文件夹“GUI”,其中包含特定于 kivy 的 *.kv 文件。包含此 GUI 文件夹的 src 文件夹包含在生成的包中,当我尝试启动程序时,*.kv 文件仍然丢失。因此,我尝试将 GUI 文件夹复制到我打包的“main”所在的同一文件夹中,并且 *.kv 文件不再丢失。为什么 PyInstaller 会复制整个 src 文件夹,但无法正确检测 GUI 文件夹? 我得到的下一个错误与 sqlalchemy 有关。因为我已经添加了一些 sqlalchemy 钩子,所以我认为打包的应用程序无法找到我用来存储数据的 data.db。这个位于我正在打包的 main.py 上方的一个文件夹中。它包含在结果中,但不在正确的位置。如果我将 data.db 复制到结果主目录上方的一个文件夹中,则此错误也将得到解决。 我的最后一个错误导致包无法工作,这又是由一些特定于 kivy 的东西引起的。错误消息说,文件 [包目录]/kivy/data/style.kv 丢失。实际上甚至没有文件夹“kivy”。我在 kivy 源中搜索了这个文件,将它复制到正确的目录,现在它可以在我的系统上运行。 现在我想知道,为什么我必须手动将所有这些文件复制到生成的目录中。我怎样才能告诉 PyInstaller 事先包含这些文件? 它可以在我的系统(我打包它的地方)上运行,但在我的第二个系统(Ubuntu 12.04LTS 64 位,关于错误的 OpenGL 版本的一些错误)上,在测试系统上(fedora,根本没有错误,只有@987654326 @) 或我大学的计算机上(Debian 3.2.57 64 位,`./main: /lib/x86_64-linux-gnu/libc.so.6: 未找到版本 GLIBC_2.14(/libz.所以.1).

我的朋友在他的 Windows 系统上使用了 PyInstaller,也遇到了一些问题(他还必须手动将上述文件/文件夹添加到包中),但最终它在 Win7 和 Win8 上同样适用。

如何使用 PyInstaller 为其他 Linux 系统以及我自己的系统制作可执行文件?我到底对main.spec 文件做了什么?或者有没有更好的方法来为 python 应用程序创建可执行文件?

【问题讨论】:

标签: python packaging kivy pyinstaller


【解决方案1】:

我不是专家,但我会分享我所知道的

将文件夹添加到生成的包中:

现在我想知道,为什么我必须将所有这些文件复制到我的结果中 手动目录。如何告诉 PyInstaller 包含这些文件 提前?

在 COLLECT 部分定义二进制文件时,您调用 Tree(),它应该使用 prefix 参数进行,因此 pyInstaller 知道将文件夹 accessmail 放在与“src”文件夹相关的位置:

Tree("/home/grafgustav/Python/ICCHP/accessmail", prefix='..')

但我从未尝试过以'..' 为前缀,必须测试它。

将文件添加到生成的包中:

打包的应用程序无法 找到我用来存储数据的 data.db。这个位于一个 我正在打包的 main.py 上方的文件夹。它包含在结果中, 但位置不对。

要将任意文件添加到二进制文件中,您只需创建一个具有 3 个值的元组,如下所示:

a.binaries += [(file_address, file_result_address, 'DATA')]

file_result_address 是文件将保留在结果包中的位置。

要添加更多文件,只需在“[]”之间添加更多元组:

[(addr,addr,type), (addr,addr,type), ...]

使其适用于多个系统:

我可以给出的第一个提示是尝试在 32 位系统上编译,这样它就可以在 32 位和 64 位系统上运行。

正如this post 第 3 节所建议的,您可能会尝试从包中删除系统库并将它们添加为依赖项,因此它将使用本机库。上面的链接在.spec 中提供了一个python 函数来完成这项工作。

制作单个二进制文件而不是包含所有依赖项的文件夹:

如何使用 PyInstaller 为其他 Linux 系统以及我自己的系统制作可执行文件?

如果您想要一个二进制文件作为输出而不是一个包含所有依赖项的文件夹,您需要使用 --onefile 选项创建一个 .spec 文件。之后您可以将相关部分复制到您的代码中:

pyinstaller --onefile myscript.py

你可以在官方pyinstaller documentation获取更多信息,对我帮助很大。

希望对你有帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-06
    • 2023-03-26
    • 1970-01-01
    • 2018-06-30
    • 1970-01-01
    • 2015-09-24
    相关资源
    最近更新 更多