Search code examples
packaginggtk3pygobjectpynsist

Package PyGObject Python 3 program with pynsist?


I would like to package a Python3-PyGObject program with pynsist. The repository has an example for PyGTK and it made me think that it shouldn't be too hard to change the example.

The example can be found here:

In this file (https://github.com/takluyver/pynsist/blob/master/examples/pygtk/grab_files.sh) I think one just has to grab the files targeting GTK 3 (http://www.gtk.org/download/win32.php):

wget -O gtkbundle.zip http://win32builder.gnome.org/gtk+-bundle_3.6.4-20130921_win32.zip
wget -O pygobject.exe http://sourceforge.net/projects/pygobjectwin32/files/pygi-aio-3.14.0_rev12-setup.exe/download
wget -O pycairo.zip http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/cairo_1.10.2-2_win32.zip

I am not sure what to do with the fourth line, because it is my current understanding that those bindings should already be inside the gtk or pygobject bundle:

 wget -O pygtk.exe http://ftp.gnome.org/pub/GNOME/binaries/win32/pygtk/2.24/pygtk-2.24.0.win32-py2.7.exe

I then tried to customize this file (https://github.com/takluyver/pynsist/blob/master/examples/pygtk/installer.cfg) to include (use gi instead of gi.repository):

[Include]
packages=gi

This resulting error is:

raise ExtensionModuleMismatch(extensionmod_errmsg % ('Windows', path)) nsist.copymodules.ExtensionModuleMismatch: Found an extension module that will not be usable on Windows: /usr/lib/python3/dist-packages/gi/_gi.cpython-34m-x86_64-linux-gnu.so Put Windows packages in pynsist_pkgs/ to avoid this.

Does anyone know what the correct approach for a program (like e.g. one of these: https://python-gtk-3-tutorial.readthedocs.org) would be?

Edit 1

After packaging and installing the program on Windows, starting the test-program produces the following traceback:

Traceback (most recent call last):
  File "C:\Program Files (x86)\hellogtk\hellogtk.launch.pyw", line 31, in <module>
    from gtk_test import main
  File "C:\Program Files (x86)\hellogtk\pkgs\gtk_test.py", line 3, in <module>
    from gi.repository import Gtk
  File "C:\Program Files (x86)\hellogtk\pkgs\gi\__init__.py", line 42, in <module>
    from . import _gi
ImportError: DLL load failed: The specified module could not be found.

It is odd that this ImportError occurs because there is a _gi.pyd-file in the same directory (gi) as the __init__.py

This is the current layout:

 - directory
 |- pynsist_pkgs
 |-- cairo
 |--- _cairo.pyd
 |--- __init__.py
 |-- gi
 |--- _gobject
 |--- overrides
 |--- repository
 |--- __init__.py
 |--- _gi.pyd
 |--- ...
 |-- gtk
 |--- bin
 |--- etc
 |--- lib
 |--- manifest
 |--- share
 |-- dbus
 |--- __init__.py
 |--- ...
 |-- gnome
 |--- ...
 |-- pygtkcompat
 |--- ...
 |-- _dbus_bindings.pyd
 |-- _dbus_glib_bindings.pyd
 |-- ...
 |- gtk_test.py
 |- grab_files.sh
 |- installer.cfg
 |- gtk_preamble.py

And I used the py-3.4-64 folder of the pygobject bindings. The Linux I am creating the package on is 64 bit, and the Windows I am running the program is also 64 bit.

Edit 2:

Using Dependency-Walker I can see that 2 DLLs are missing: GPSVC.DLL and IESHIMS.DLL.

Edit 3:

I found those 2 DLLs on the system and copied them in different directories of the test-program, but it didn't work.

Edit 4:

This might be useful for the import-error:


Solution

  • I worked together with Thomas K, the author of pynsist, to solve this. And I do want to advertise that it is a great tool, with very good support, and it makes packaging orders of magnitudes easier in my opinion.

    There were a number of mistakes in my approach (see question), so it might be easier to just describe the correct approach:

    Download dependencies

    The only dependency needed for a program that only imports:

     from gi.repository import Gtk
    

    is the most recent pygi-aio (currently pygi-aio-3.14) bundle that can be downloaded here (The example in the pynsist-repository has a download script, but i might need to be updated for newer releases):

    Extract dependencies

    The PyGObject/PyGI example that has now been merged into the pynsist-repository, comes with a script that extracts the necessary dependencies from the bundle (See: https://github.com/takluyver/pynsist/tree/master/examples/pygi_mpl_numpy).

    Most importantly it extracts the contents of the bindings zip file (Modify the script for the targeted Python version and bitness) and copies them into the pynsist_pkgs folder:

      - cairo
      - dbus
      - gi
      - gnome
      - pygtkcompat
    

    Then it extracts and copies the subdependencies into the pynsist_pkgs/gnome/ folder. As lazka pointed out, the minimum requirements for a typical minimal Gtk-program are (each library has a pygi/noarch and pygi/[TargetedArchitecture] zip file):

     - ATK
     - Base
     - Gdk
     - GDKPixbuf
     - GTK
     - JPEG
     - Pango
     - WebP
     - TIFF
    

    Build the installer

    The installer was then build in my case using:

     python3 -m nsist installer.cfg
    

    The installer.cfg is also in the repositories example folder. It only requires gnome to be listed (The subdependecies in the gnome folder behave as one unit).

    Note about the pygi-aio bundle

    When the pygi-aio is installed on a Windows-machine, the installer performs some post-installation compiling steps. This might become an issue if you are using this approach, because it only extracts the dependencies. In some cases you might need to run an exe file (comes with the bundle) and copy the compiled files back into your build directory. I describe the only problem I had here:

    And there is a bug report with more information here:

    Working example

    You can get the example here: