Kivy:编译为单个可执行文件
Kivy: compiling to a single executable
在 kivy 论坛上没有得到回复,所以在这里试试。
当我将教程 pong 代码编译为一个文件可执行文件时,我仍然必须将 pong.kv 文件包含在同一文件夹中,以便它成为 运行。
否则,启动 exe 时会出现以下错误:
GL: EXT_framebuffer_object is supported
[INFO ] [GL ] OpenGL version
[INFO ] [GL ] OpenGL vendor
[INFO ] [GL ] OpenGL renderer
[INFO ] [GL ] OpenGL parsed version: 2, 1
[INFO ] [GL ] Shading version
[INFO ] [GL ] Texture max size
[INFO ] [GL ] Texture max units
[INFO ] [Window ] auto add sdl2 input provider
[INFO ] [Window ] virtual keyboard not allowed,
single mode, not docked
Traceback (most recent call last):
File "", line 81, in
File "c:\python34\lib\site-packages\kivy\app.py", line 802, in
run
root = self.build()
File "", line 75, in build
File "", line 20, in serveBall
AttributeError: 'NoneType' object has no attribute 'center'
main returned -1
如何将它作为一个可执行文件提供给 运行。这是我的 pong.spec 文件:
# -*- mode: python -*-
from kivy.deps import sdl2, glew
block_cipher = None
a = Analysis(['Code\main.py'],
pathex=['E:\Development\Pong'],
binaries=None,
datas=None,
hiddenimports=[],
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)
a.datas += [('Code\pong.kv', 'E:\Development\Pong\Code\pong.kv', 'DATA')]
exe = EXE(pyz,Tree('Code'),
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
name='pong',
debug=False,
strip=False,
upx=True,
console=True , icon='pong.ico')
请注意,我试图将 pong.kv 包含在数据列表中,但这没有帮助。
谢谢,
-拉吉
如果你不关心代码长度,使用Builder.load_string
将kv数据加载到.py文件中怎么样?这样,整个代码都保存在您的 python 脚本中,这可能有助于将其编译为 .exe。
根据KeyWeeUsr (Bundling data files with PyInstaller and Using PyInstaller to make EXEs from Python scripts)提供的链接,结合Kivy的资源路径方法,这里有一个可行的解决方案。我觉得它的边缘有点粗糙,因为它使用 SYS._MEIPASS(我更喜欢 public API)并且需要在您的 Python 代码中添加一个代码片段。但是,该解决方案适用于 Windows 和 Mac,因此将共享。
假设我有以下代码层次结构:
MyCode/
MyApp.py (This is the main program)
myapp.kv (This is the associated kv file)
MyData/ (This is where data is located that the app uses)
myapp.icns (e.g. icon file for mac)
myapp.ico (e.g. icon file for windows)
Build/
mac/
myapp.spec (spec file to build on mac platform)
pc/
myapp.spec (spec file to build on windows platform)
MyHiddenImports/ (Folder containing python files for hidden imports)
我在示例中添加了一个 MyHiddenImports 文件夹,以防您的代码还在 运行 时间内将另一个包含 python 代码的文件夹附加到 sys.path。
在MyApp.py中添加以下内容:
def resourcePath():
'''Returns path containing content - either locally or in pyinstaller tmp file'''
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS)
return os.path.join(os.path.abspath("."))
if __name__ == '__main__':
kivy.resources.resource_add_path(resourcePath()) # add this line
my_app = MyApp()
resources_add_path() 告诉 Kivy 去哪里寻找 data/.kv 文件。例如,在 Mac 上,当 运行 运行 pyinstaller 应用程序时,它指向 /private/var/folders/80/y766cxq10fb_794019j7qgnh0000gn/T/_MEI25602,而在 windows 中,它指向 c:\users\raj\AppData\Local\Temp_MEI64zTut(这些文件夹在退出应用程序后被删除,并在再次启动时创建另一个名称)。
我使用以下命令创建了初始 Mac 模板规范文件:
pyinstaller --onefile -y --clean --windowed --name myapp --icon=../../Code/Data/myapp.icns --exclude-module _tkinter --exclude-module Tkinter --exclude-module enchant --exclude-module twisted ../../Code/MyApp.py
这是修改后的 Mac OS 规范文件:
# -*- mode: python -*-
block_cipher = None
a = Analysis(['../../Code/MyApp.py'],
pathex=['/Users/raj/Development/Build/mac',
'../../MyHiddenImports'],
binaries=None,
datas=None,
hiddenimports=['MyHiddenImports'],
hookspath=[],
runtime_hooks=[],
excludes=['_tkinter', 'Tkinter', 'enchant', 'twisted'],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
a.datas += [('myapp.kv', '../../MyCode/my.kv', 'DATA')]
exe = EXE(pyz, Tree('../../Code/Data', 'Data'),
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name='myapp',
debug=False,
strip=False,
upx=True,
console=False , icon='../../Code/Data/myapp.icns')
app = BUNDLE(exe,
name='myapp.app',
icon='../../Code/Data/myapp.icns',
bundle_identifier=None)
注意事项:我在pathex中添加了隐藏导入路径,并在hiddenimports中引用了包。我将 myapp.kv 文件附加到 a.datas,以便将其复制到应用程序中。在 EXE 中,我添加了数据树。我包含了前缀参数,因为我希望将 Data 文件夹复制到应用程序中(而不是让子项位于根级别)。
为了编译代码以创建应用程序并将其放入 dmg 文件中,我有一个执行以下操作的 make-myapp 脚本:
pyinstaller -y --clean --windowed myapp.spec
pushd dist
hdiutil create ./myapp.dmg -srcfolder myapp.app -ov
popd
cp ./dist/myapp.dmg .
同样,这里是 windows 规范文件:
# -*- mode: python -*-
from kivy.deps import sdl2, glew
block_cipher = None
a = Analysis(['..\..\Code\Cobbler.py'],
pathex=['E:\Development\MyApp\Build\pc',
'..\..\MyHiddenImports'],
binaries=None,
datas=None,
hiddenimports=['MyHiddenImports'],
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)
a.datas += [('myapp.kv', '../../Code/myapp.kv', 'DATA')]
exe = EXE(pyz, Tree('..\..\Code\Data','Data'),
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
name='myapp',
debug=False,
strip=False,
upx=True,
console=False, icon='..\..\Code\Data\myapp.ico' )
并编译 windows 应用程序:
python -m PyInstaller myapp.spec
在 kivy 论坛上没有得到回复,所以在这里试试。
当我将教程 pong 代码编译为一个文件可执行文件时,我仍然必须将 pong.kv 文件包含在同一文件夹中,以便它成为 运行。 否则,启动 exe 时会出现以下错误:
GL: EXT_framebuffer_object is supported [INFO ] [GL ] OpenGL version [INFO ] [GL ] OpenGL vendor [INFO ] [GL ] OpenGL renderer [INFO ] [GL ] OpenGL parsed version: 2, 1 [INFO ] [GL ] Shading version [INFO ] [GL ] Texture max size [INFO ] [GL ] Texture max units [INFO ] [Window ] auto add sdl2 input provider [INFO ] [Window ] virtual keyboard not allowed, single mode, not docked Traceback (most recent call last): File "", line 81, in File "c:\python34\lib\site-packages\kivy\app.py", line 802, in run root = self.build() File "", line 75, in build File "", line 20, in serveBall AttributeError: 'NoneType' object has no attribute 'center' main returned -1
如何将它作为一个可执行文件提供给 运行。这是我的 pong.spec 文件:
# -*- mode: python -*-
from kivy.deps import sdl2, glew
block_cipher = None
a = Analysis(['Code\main.py'],
pathex=['E:\Development\Pong'],
binaries=None,
datas=None,
hiddenimports=[],
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)
a.datas += [('Code\pong.kv', 'E:\Development\Pong\Code\pong.kv', 'DATA')]
exe = EXE(pyz,Tree('Code'),
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
name='pong',
debug=False,
strip=False,
upx=True,
console=True , icon='pong.ico')
请注意,我试图将 pong.kv 包含在数据列表中,但这没有帮助。
谢谢, -拉吉
如果你不关心代码长度,使用Builder.load_string
将kv数据加载到.py文件中怎么样?这样,整个代码都保存在您的 python 脚本中,这可能有助于将其编译为 .exe。
根据KeyWeeUsr (Bundling data files with PyInstaller and Using PyInstaller to make EXEs from Python scripts)提供的链接,结合Kivy的资源路径方法,这里有一个可行的解决方案。我觉得它的边缘有点粗糙,因为它使用 SYS._MEIPASS(我更喜欢 public API)并且需要在您的 Python 代码中添加一个代码片段。但是,该解决方案适用于 Windows 和 Mac,因此将共享。
假设我有以下代码层次结构:
MyCode/ MyApp.py (This is the main program) myapp.kv (This is the associated kv file) MyData/ (This is where data is located that the app uses) myapp.icns (e.g. icon file for mac) myapp.ico (e.g. icon file for windows) Build/ mac/ myapp.spec (spec file to build on mac platform) pc/ myapp.spec (spec file to build on windows platform) MyHiddenImports/ (Folder containing python files for hidden imports)
我在示例中添加了一个 MyHiddenImports 文件夹,以防您的代码还在 运行 时间内将另一个包含 python 代码的文件夹附加到 sys.path。
在MyApp.py中添加以下内容:
def resourcePath():
'''Returns path containing content - either locally or in pyinstaller tmp file'''
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS)
return os.path.join(os.path.abspath("."))
if __name__ == '__main__':
kivy.resources.resource_add_path(resourcePath()) # add this line
my_app = MyApp()
resources_add_path() 告诉 Kivy 去哪里寻找 data/.kv 文件。例如,在 Mac 上,当 运行 运行 pyinstaller 应用程序时,它指向 /private/var/folders/80/y766cxq10fb_794019j7qgnh0000gn/T/_MEI25602,而在 windows 中,它指向 c:\users\raj\AppData\Local\Temp_MEI64zTut(这些文件夹在退出应用程序后被删除,并在再次启动时创建另一个名称)。
我使用以下命令创建了初始 Mac 模板规范文件:
pyinstaller --onefile -y --clean --windowed --name myapp --icon=../../Code/Data/myapp.icns --exclude-module _tkinter --exclude-module Tkinter --exclude-module enchant --exclude-module twisted ../../Code/MyApp.py
这是修改后的 Mac OS 规范文件:
# -*- mode: python -*-
block_cipher = None
a = Analysis(['../../Code/MyApp.py'],
pathex=['/Users/raj/Development/Build/mac',
'../../MyHiddenImports'],
binaries=None,
datas=None,
hiddenimports=['MyHiddenImports'],
hookspath=[],
runtime_hooks=[],
excludes=['_tkinter', 'Tkinter', 'enchant', 'twisted'],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
a.datas += [('myapp.kv', '../../MyCode/my.kv', 'DATA')]
exe = EXE(pyz, Tree('../../Code/Data', 'Data'),
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name='myapp',
debug=False,
strip=False,
upx=True,
console=False , icon='../../Code/Data/myapp.icns')
app = BUNDLE(exe,
name='myapp.app',
icon='../../Code/Data/myapp.icns',
bundle_identifier=None)
注意事项:我在pathex中添加了隐藏导入路径,并在hiddenimports中引用了包。我将 myapp.kv 文件附加到 a.datas,以便将其复制到应用程序中。在 EXE 中,我添加了数据树。我包含了前缀参数,因为我希望将 Data 文件夹复制到应用程序中(而不是让子项位于根级别)。
为了编译代码以创建应用程序并将其放入 dmg 文件中,我有一个执行以下操作的 make-myapp 脚本:
pyinstaller -y --clean --windowed myapp.spec pushd dist hdiutil create ./myapp.dmg -srcfolder myapp.app -ov popd cp ./dist/myapp.dmg .
同样,这里是 windows 规范文件:
# -*- mode: python -*-
from kivy.deps import sdl2, glew
block_cipher = None
a = Analysis(['..\..\Code\Cobbler.py'],
pathex=['E:\Development\MyApp\Build\pc',
'..\..\MyHiddenImports'],
binaries=None,
datas=None,
hiddenimports=['MyHiddenImports'],
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)
a.datas += [('myapp.kv', '../../Code/myapp.kv', 'DATA')]
exe = EXE(pyz, Tree('..\..\Code\Data','Data'),
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
name='myapp',
debug=False,
strip=False,
upx=True,
console=False, icon='..\..\Code\Data\myapp.ico' )
并编译 windows 应用程序:
python -m PyInstaller myapp.spec