3

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:

Community
  • 1
  • 1
tobias47n9e
  • 2,233
  • 3
  • 28
  • 54
  • Try putting just `gi` in packages - it's supposed to be top-level importable names. I'm downloading the pygobject bundle to see if that's the right thing. – Thomas K Mar 01 '15 at 17:12
  • It appears that `pygi-aio-3.14.0_rev12-setup.exe` is not a self executing zip file like the pygtk installer I used before, so calling unzip on it won't work. I'm not sure how best to extract the files from it. – Thomas K Mar 01 '15 at 17:19
  • @ThomasK: Just using `gi`seems to be the right approach. Now I get a more meaningful error message: `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.` – tobias47n9e Mar 01 '15 at 17:24
  • 1
    Yep. The idea is that you run `./grab-files.sh` beforehand, and it puts the Windows versions of those libraries in `pynsist_pkgs`, where they'll be used instead of your Linux libraries. I've worked out that that pygi installer can be unpacked using `7z` (`apt-get install p7zip-full` on an Ubuntu system). That unpacks 1.5 GB in several directories (!) - it looks like you'll need to work out which bits you need and then do a second round of unpacking archives to get the actual files. – Thomas K Mar 01 '15 at 17:29
  • @ThomasK: I tried all kinds of combinations but could only get the installer working. The resulting program does not show the window. I can only get the PyGTK example to work properly. It is a little hard for me to grasp what is going wrong. – tobias47n9e Mar 01 '15 at 21:49
  • 1
    If you manage to install and try to run the application, and it crashes, it should be writing the traceback to a log file in `%APPDATA%`. On a Windows 7 system, that's typically `C:\Users\{username}\AppData\Roaming`. That should help tell you what's going wrong. Or you can start a command prompt, cd to the installed directory in Program Files and run `py MyApp.launch.pyw`. – Thomas K Mar 02 '15 at 02:11
  • That error message ('DLL load failed') means it's failing to find another DLL that that one (.pyd files are Python DLLs) requires. [Dependency walker](http://www.dependencywalker.com/) might help you figure it out. – Thomas K Mar 03 '15 at 19:29
  • (BTW, thanks for your patience working this out. Pynsist is quite new, and you're probably the first person to try it with the new pygobject interface) – Thomas K Mar 03 '15 at 19:31
  • @ThomasK: I found 2 missing dll's using dw. Still have to read up why they are missing. It is actually a lot of fun to figure things out, but packaging is somehow very difficult for me. I should have taken more programming courses in college :) – tobias47n9e Mar 03 '15 at 20:33
  • TBH, I think that packaging pygobject apps for Windows is difficult for anyone. Did you find the DLLs you need? [This example](https://wiki.gnome.org/Projects/PyGObject?action=AttachFile&do=view&target=setup.py) of a script to freeze the app with cx_Freeze might be informative. – Thomas K Mar 03 '15 at 22:10
  • @ThomasK: I added the missing DLLs to my question, but I am still reading what they are about. This question seems to be similar: http://stackoverflow.com/questions/1877098/nunit-missing-gpsvc-dll-on-windows-7-64 – tobias47n9e Mar 03 '15 at 22:18
  • Aha. From that question, it sounds like a 64/32 bit distinction may be relevant. If your test system is 64-bit, maybe it's worth packaging with 64-bit Python and pygobject, at least to get the kinks worked out. – Thomas K Mar 03 '15 at 22:33
  • @ThomasK: I tried but it didn't change the problems and DW is till looking for those 2 packages. – tobias47n9e Mar 04 '15 at 08:08
  • If you copy those DLLs into the same folder as `_gi.pyd`, does it find them? – Thomas K Mar 04 '15 at 23:29
  • @ThomasK: Still not luck. The DLLs still show up as missing, and from different discussion I found, it might also be a false warning by dependency walker? In any case the traceback now complains about non-valid Win32 application. – tobias47n9e Mar 05 '15 at 11:15
  • I think that error (about a non-valid Win32 application) can mean that you've got 64-bit and 32-bit binaries mixed. But there may also be other causes for it. Possibly the best way forwards would be to install Python and pygobject on a Windows system, make sure it works and find out how it fits together. – Thomas K Mar 05 '15 at 23:47
  • @ThomasK: I installed the PyGobject bundle for Python 3.4 64 bit and that at least works. I can start Gedit and Glade. The bundle also includes GTK I think, but I am not sure about Cairo. I will see if I can get it working with that bundle as my only requirment. – tobias47n9e Mar 06 '15 at 11:20
  • @ThomasK: I now filed a bug at https://bugzilla.gnome.org/show_bug.cgi?id=745818 – tobias47n9e Mar 07 '15 at 17:56
  • Now that you've [worked this out](https://github.com/takluyver/pynsist/tree/master/examples/pygi_mpl_numpy), do you want to answer your own question, so future people reading this can quickly see the result? – Thomas K Apr 03 '15 at 01:17
  • Was a little busy this week catching up from the flu. Answer is done, and thank you again for very much helping out along the way! – tobias47n9e Apr 03 '15 at 14:12
  • Thanks! Sorry to hear you were ill; I hope you're fully recovered now. – Thomas K Apr 03 '15 at 16:46

1 Answers1

2

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:

Community
  • 1
  • 1
tobias47n9e
  • 2,233
  • 3
  • 28
  • 54