2

I'm using PyGObject/GTK+ with Python3.7 on Windows and is worried about how to package my app. With official Python ecosystem, it's easy to use freezers and venvs. However, the PyGObject and GTK+ on Windows requires the MingW environment to run.

Does this mean that I have to package the entire MingW, along with GTK+? How should I freeze the app?

kakyo
  • 10,460
  • 14
  • 76
  • 140

1 Answers1

6

Since no one cares soon enough, I'll report my findings here. The short answer, as of the date I write this post, is: The PyGObject eco-system is not commercial-ready on Windows, although nothing stops you from shipping a functional app.

The deal-breaker is the lack of functional freezers on Windows for PyGOBject. So you can't really ship a closed-source commercial product with it (although one could argue that the entire Python eco-system is not made for that). The freezers that I tried:

  1. The officially recommended PyInstaller right now does not install with the officially recommended msys/MingGW universe; Even after building PyInstaller from source, the frozen .exe crashes with complaints about missing modules. Below is the crash report from a hello-world app.
$ app.exe
[8340] mod is NULL - structTraceback (most recent call last):
  File "C:/Apps/msys64/mingw64/lib/python3.7/struct.py", line 13, in <module>
    from _struct import *
ModuleNotFoundError: No module named '_struct'
[8340] mod is NULL - pyimod02_archiveTraceback (most recent call last):
  File "C:/Apps/msys64/mingw64/lib/python3.7/site-packages/pyinstaller-3.5-py3.7.egg/PyInstaller/loader/pyimod02_archive.py", line 28, in <module>
    import struct
ModuleNotFoundError: No module named 'struct'
[8340] mod is NULL - pyimod03_importersTraceback (most recent call last):
  File "C:/Apps/msys64/mingw64/lib/python3.7/site-packages/pyinstaller-3.5-py3.7.egg/PyInstaller/loader/pyimod03_importers.py", line 24, in <module>
    from pyimod02_archive import ArchiveReadError, ZlibArchiveReader
ModuleNotFoundError: No module named 'pyimod02_archive'
Traceback (most recent call last):
  File "site-packages/pyinstaller-3.5-py3.7.egg/PyInstaller/loader/pyiboot01_bootstrap.py", line 15, in <module>
ModuleNotFoundError: No module named 'pyimod03_importers'
[8340] Failed to execute script pyiboot01_bootstrap
  1. cx_Freeze, another prominent alternative, does not build/install on MingW, either. You end up with gcc woes, no matter how many gcc variants you install.
  2. py2exe is now abandonware since Python 3.4.

Since a PyGObject app still runs with MinGW python, it's not impossible to ship such an app for Windows. But that means you'll go with the big baggage and figure out a way to pack everything yourself. Let alone maintain the whole mess. Mind you that the procedure will be different on Mac if your app is cross-platform. PyInstaller works on Mac according to my test.

QuodLibet provides an example of how to ship an open-source software based on PyGObject. Unfortunately, as of today, the upstream's packaging procedure fails at the build.sh run on my Windows 10:

copying data/quodlibet.zsh -> E:\_dev\quodlibet\win_installer\_build_root\mingw64\share\zsh\vendor-completions\_quodlibet
Traceback (most recent call last):
  File "E:/_dev/quodlibet/win_installer/misc/depcheck.py", line 141, in <module>
    main(sys.argv)
  File "E:/_dev/quodlibet/win_installer/misc/depcheck.py", line 130, in main
    libs = get_things_to_delete(sys.prefix)
  File "E:/_dev/quodlibet/win_installer/misc/depcheck.py", line 108, in get_things_to_delete
    for lib in get_dependencies(path):
  File "E:/_dev/quodlibet/win_installer/misc/depcheck.py", line 66, in get_dependencies
    data = data.decode("utf-8")
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa3 in position 72: invalid start byte

This turns out to be an easy fix: locale issue on non-UTF8 Windows. A trivial patch would be replacing "utf-8" with locale.getdefaultlocale(). After that, the build succeeds.

However, the global distribution issues remain challenging:

  • Bloated pipeline: The officially recommended msys2 build system basically drags the entire GNOME universe and much of the Python universe to your machine, while you may already have a Python environment on your native Windows. It proves hard to cherry-pick the necessary dependencies among this whole pile of stuff.
  • Extra C pipeline required to build the executable. To build a Windows executable without a freezer, you must create your app as a Python package (big hassle), install it to your msys2-Python site-packages (another setup.py hassle), and then build a wrapper C application using the Python C API (opaque hassle). The process is not transparent, especially when Python packaging system is sensitive to working directory and path differences. Launching the executable can easily go wrong without much debug info.
  • Manual stripping. As mentioned above, you must manually cherry-pick dependencies or your app would be shipped with basically the entire msys2/MinGW universe that's worth 100MB+ for a hello-world app.
kakyo
  • 10,460
  • 14
  • 76
  • 140