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.

Другие вопросы по тегам