Packaging Kivy apps written in Python 3, targeting Windows using Nuitka

dessant edited this page Oct 24, 2015 · 5 revisions
Clone this wiki locally

Note

This guide was tested only with the provided sample app, you may need to add, remove or uncomment modules in dependencies.py for your own app, if Nuitka does not detect them (usually when hidden imports are used). Data files and some DLLs are not copied over, those should be manually added to the resulting main.dist folder.

Preparing the environment

SCons (used by Nuitka) is not compatible with Python 3, installing Python 2.7 is necessary, preferably to C:\Python27.

MinGW or Visual Studio can be used as a compiler, MinGW being included by default in the Kivy SDK. When using Visual Studio Community 2015, the C++ tools must be selected at installation time.

Download the Kivy SDK for Windows.

Updating Kivy to the development version is recommended, for a guide follow: Use development Kivy.

Launch kivy.bat, which is located in the Kivy SDK, and install Nuitka:

pip install nuitka

Preparing the app

The compiled app with disabled console will only run if stdin, stdout and stderr are redirected. The KIVY_DATA_DIR environment variable should be also set, otherwise Kivy will not find some of its asssets.

The following sample app will be packaged in this guide, call the prep_win_standalone function the same way at the start of your main.py:

import sys
from os import environ
from os.path import join, dirname, realpath


def prep_win_standalone():
    class DummyStream():
        def __init__(self):
            pass

        def write(self, data):
            pass

        def read(self, data):
            pass

        def flush(self):
            pass

        def close(self):
            pass

    sys.stdin = DummyStream()
    sys.stdout = DummyStream()
    sys.stderr = DummyStream()
    sys.__stdin__ = DummyStream()
    sys.__stdout__ = DummyStream()
    sys.__stderr__ = DummyStream()

    exec_dir = dirname(realpath(sys.argv[0]))
    environ['KIVY_DATA_DIR'] = join(exec_dir, 'data')

prep_win_standalone()


from kivy.app import App
from kivy.lang import Builder

root = Builder.load_string('''
BoxLayout:
    Button:
        text: 'Nuitka!'
''')


class TestApp(App):
    def build(self):
        return root

if __name__ == '__main__':
    TestApp().run()

Create dependencies.py in the folder where main.py is located, and add the following imports to it:

# uncomment this if you need to package pygame
# import pygame
# import pygame.event
# import pygame.video
# import pygame.image
# import pygame.display
# import pygame

# external modules
import kivy.cache
import kivy.atlas
import kivy.network
import kivy.network.urlrequest
import kivy.lib.osc
import kivy.lib.osc.OSC
import kivy.lib.osc.oscAPI
import kivy.lib.mtdev
import kivy.lib.sdl2
import kivy.factory_registers
import kivy.input.recorder
import kivy.input.providers
import kivy.input.providers.tuio
import kivy.input.providers.mouse
import kivy.input.providers.wm_common
import kivy.input.providers.wm_touch
import kivy.input.providers.wm_pen
import kivy.input.providers.hidinput
import kivy.input.providers.linuxwacom
import kivy.input.providers.mactouch
import kivy.input.providers.mtdev

# compiled modules
import kivy.event
import kivy.graphics.buffer
import kivy.graphics.c_opengl_debug
import kivy.graphics.compiler
import kivy.graphics.context_instructions
import kivy.graphics.fbo
import kivy.graphics.instructions
import kivy.graphics.opengl
import kivy.graphics.opengl_utils
import kivy.graphics.shader
import kivy.graphics.stenctil_instructions
import kivy.graphics.texture
import kivy.graphics.transformation
import kivy.graphics.vbo
import kivy.graphics.vertex
import kivy.graphics.vertex_instructions
import kivy.graphics.tesselator
import kivy.graphics.svg
import kivy.properties

# core
# import kivy.core.audio.audio_gstplayer
# import kivy.core.audio.audio_pygst
import kivy.core.audio.audio_sdl2
# import kivy.core.audio.audio_pygame
# import kivy.core.camera.camera_avfoundation
# import kivy.core.camera.camera_pygst
# import kivy.core.camera.camera_opencv
# import kivy.core.camera.camera_videocapture
import kivy.core.clipboard.clipboard_sdl2
# import kivy.core.clipboard.clipboard_android
# import kivy.core.clipboard.clipboard_pygame
# import kivy.core.clipboard.clipboard_dummy
# import kivy.core.image.img_imageio
# import kivy.core.image.img_tex
# import kivy.core.image.img_dds
import kivy.core.image.img_sdl2
# import kivy.core.image.img_pygame
# import kivy.core.image.img_pil
# import kivy.core.image.img_gif
# import kivy.core.spelling.spelling_enchant
# import kivy.core.spelling.spelling_osxappkit
import kivy.core.text.text_sdl2
# import kivy.core.text.text_pygame
# import kivy.core.text.text_sdlttf
# import kivy.core.text.text_pil
# import kivy.core.video.video_gstplayer
# import kivy.core.video.video_pygst
# import kivy.core.video.video_ffmpeg
# import kivy.core.video.video_pyglet
# import kivy.core.video.video_null
import kivy.core.window.window_sdl2
# import kivy.core.window.window_egl_rpi
# import kivy.core.window.window_pygame
# import kivy.core.window.window_sdl
# import kivy.core.window.window_x11

Launch kivy.bat and go to your application directory, assuming your app (including main.py) is in C:\test_app\:

cd "C:\test_app\"

Packaging with Visual Studio

Set the Visual Studio paths (verify that the file path exists, it may differ, depending on the VS or Windows version):

"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall" x86

Start packaging (the --msvc version may be changed):

nuitka --msvc=14.0 --python-version=3.4 --recurse-plugins=dependencies.py --standalone --windows-disable-console --remove-output main.py

Packaging with MinGW

nuitka --mingw --python-version=3.4 --recurse-plugins=dependencies.py --standalone --windows-disable-console --remove-output main.py

Copying assets and SDL2 dependencies

After the compilation is done (it may take several minutes), a folder named main.dist will be created in the app directory, holding your compiled Kivy app, with its dependencies.

Grab Kivy's data directory from <Kivy SDK path>\kivy\kivy\data or from Github, and copy it to the main.dist folder. Also copy all the DLLs located at <Kivy SDK path>\SDL2\bin into main.dist.

That's it, your application can be distributed by sharing the main.dist folder.