Kivy: компилирование в один исполняемый файл
Не получил ответа на форуме KIVY, так что попробуйте здесь.
Когда я компилирую учебный код pong как один исполняемый файл, я все равно должен включить файл pong.kv в ту же папку, чтобы он запускался. В противном случае я получаю следующую ошибку при запуске exe:
GL: поддерживается EXT_framebuffer_object [INFO] [GL] Версия OpenGL [INFO] [GL] Поставщик OpenGL [INFO] [GL] Средство визуализации OpenGL [INFO] [GL] Разобранная версия OpenGL: 2, 1 [INFO ] [GL ] Версия с затенением [INFO] [GL] Максимальный размер текстуры [INFO] [GL] Максимальный размер текстуры [INFO] [Окно] автоматическое добавление поставщика ввода sdl2 [INFO] [Окно] виртуальная клавиатура не разрешена, одиночный режим, не закреплена Traceback (последний вызов последний): файл "", строка 81, в файле "c:\python34\lib\site-packages\kivy\app.py", строка 802, в файле run root = self.build() "", строка 75, в файле сборки "", строка 20, в serveBall AttributeError: у объекта 'NoneType' нет атрибута 'center' main возвращено -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 в список данных, но это не помогло.
Спасибо, Радж
2 ответа
Основываясь на ссылках, предоставленных KeyWeeUsr (объединение файлов данных с PyInstaller и использование PyInstaller для создания EXE- файлов из скриптов Python) и совмещая это с методом пути ресурсов Kivy, вот работоспособное решение. Я чувствую, что это немного грубо по краям, потому что он использует SYS._MEIPASS (я бы предпочел публичный API) и требует добавления фрагмента кода в ваш код Python. Тем не менее, решение работает как на Windows, так и на Mac, поэтому поделится.
Предположим, у меня есть следующая иерархия кода:
MyCode / MyApp.py (это основная программа) myapp.kv (это связанный файл kv) MyData/ (Здесь находятся данные, которые использует приложение) myapp.icns (например, файл значков для Mac) myapp.ico (например, файл значков для Windows) Build/ макинтош / myapp.spec (файл спецификации для сборки на платформе Mac) ПК/ myapp.spec (файл спецификации для сборки на платформе Windows) MyHiddenImports/ (папка, содержащая файлы Python для скрытого импорта)
Я добавил папку 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/folder /80/y766cxq10fb_794019j7qgnh0000gn/T/_MEI25602, а в окнах указывало на 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 Spec файл:
# -*- 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 я добавил дерево данных. Я включил префиксный аргумент, так как я хотел, чтобы папка данных копировалась в приложение (вместо того, чтобы дети сидели на корневом уровне).
Чтобы скомпилировать код для создания приложения и поместить его в файл 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
Если вас не интересует длина кода, как насчет загрузки данных kv в файл.py с помощью Builder.load_string
? Таким образом, весь код хранится внутри вашего скрипта Python, и это может помочь скомпилировать его в.exe.