Shipping PyGObject/GTK+ app on Windows with MingW

ghz 8hours ago ⋅ 5 views

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?

Answer

When packaging a PyGObject/GTK+ application on Windows, you are indeed facing some additional challenges due to the dependencies on GTK+ and the MinGW runtime. Here's a breakdown of how to handle the packaging process for a PyGObject-based app on Windows.

1. Understanding Dependencies

PyGObject on Windows relies on GTK+ for the graphical user interface and also depends on the MinGW (Minimal GNU for Windows) environment. This means that, unlike pure Python apps that only need the Python runtime and any dependencies, GTK+ requires native libraries that need to be bundled together when distributing your app.

In general, you will need to package:

  • GTK+ runtime: The GTK+ libraries (e.g., gtk-3.dll, gdk-3.dll) and their dependencies.
  • MinGW runtime: The MinGW environment is required to run GTK+ on Windows.
  • Your Python app: The Python interpreter, your application code, and any other Python dependencies.

2. Using pyinstaller to Package the App

pyinstaller is a tool that can freeze your Python application into an executable, and it supports bundling external libraries (like GTK+). However, there are some caveats for GTK+ applications, as it doesn't automatically bundle the GTK+ libraries or MinGW runtime by default.

Here’s how you can proceed:

Step-by-Step Guide

  1. Install Dependencies

    • Install GTK+ and the necessary libraries for PyGObject on Windows. You can install GTK+ on Windows using the MSYS2 package manager (which includes MinGW).

    • Install MSYS2:

      • Download MSYS2 from msys2.org.
      • Run the following commands to install GTK+ and PyGObject dependencies:
        pacman -S mingw-w64-x86_64-gtk3 mingw-w64-x86_64-python3-pygobject
        
    • Install PyGObject for Python: You can also install the Python bindings for GTK+ via pip:

      pip install PyGObject
      
  2. Create the Executable Using pyinstaller

    • You can use pyinstaller to freeze your app, but you need to ensure that the GTK+ libraries are included in the package.

    • Install pyinstaller if you haven't already:

      pip install pyinstaller
      
    • Now you can run pyinstaller to freeze the application:

      pyinstaller --onefile --windowed myapp.py
      
    • --onefile: Creates a single executable.

    • --windowed: Prevents a terminal window from opening (useful for GUI apps).

  3. Ensure GTK+ and MinGW Runtime are Included

    • By default, pyinstaller doesn't bundle GTK+ libraries or MinGW dependencies.

    • You can manually tell pyinstaller to include the necessary GTK+ libraries by specifying them in the --add-binary option. The libraries should be located in your MSYS2 environment.

      For example, if your MSYS2 environment has GTK+ in C:\msys64\mingw64\bin, you would add the following:

      pyinstaller --onefile --windowed --add-binary "C:/msys64/mingw64/bin/gtk-3.dll;." --add-binary "C:/msys64/mingw64/bin/gdk-3.dll;." myapp.py
      

      You will need to find all the required GTK+ libraries and include them with --add-binary. The ;. part ensures they are included in the same directory as the executable.

  4. Ensure All Dependencies Are Bundled

    • For more complex dependencies, you may need to manually include additional libraries that GTK+ relies on. You can use the Dependency Walker tool (or similar) to inspect the dependencies of the gtk-3.dll and make sure all necessary libraries are bundled.

    • A common GTK+ app will require several .dll files such as:

      • gdk-3.dll
      • gtk-3.dll
      • cairo-2.dll
      • pango-1.0.dll
      • atk-1.0.dll

      Make sure these are included either by using --add-binary or by manually copying them into the output directory.

  5. Final Steps

    • After running pyinstaller, it will generate a dist/ folder containing the executable (myapp.exe). Test the executable to ensure it works properly without needing the MinGW environment or GTK+ installed on the system.

    • If the executable fails to run on a clean Windows machine (without the MSYS2 environment installed), it’s likely that you haven’t included all the necessary GTK+ dependencies. In that case, revisit the previous steps to include any missing libraries.

3. Alternative Approach: Using cx_Freeze

Another option is cx_Freeze, which also supports packaging Python apps into standalone executables. However, like pyinstaller, it doesn't automatically bundle GTK+ dependencies, so you'll still need to include the necessary GTK+ libraries manually.

  1. Install cx_Freeze:

    pip install cx_Freeze
    
  2. Create the Setup Script: You can create a setup.py script that uses cx_Freeze to bundle the application and include GTK+ dependencies. Here's an example:

    from cx_Freeze import setup, Executable
    
    # Dependencies (GTK and MinGW libraries)
    include_files = [
        "C:/msys64/mingw64/bin/gtk-3.dll",
        "C:/msys64/mingw64/bin/gdk-3.dll",
        "C:/msys64/mingw64/bin/cairo-2.dll",
        # Add other GTK+ and MinGW dependencies here
    ]
    
    build_options = {
        'include_files': include_files,
    }
    
    setup(
        name="MyApp",
        version="1.0",
        description="GTK+ Application",
        options={'build_exe': build_options},
        executables=[Executable("myapp.py", targetName="myapp.exe")],
    )
    
  3. Build the Executable: Run the setup.py script:

    python setup.py build
    

    This will create a build/ folder with the bundled executable.

Conclusion

To summarize:

  • Yes, you will need to bundle the GTK+ libraries and MinGW runtime along with your app.
  • Use pyinstaller or cx_Freeze to freeze your app, and manually include the necessary GTK+ and MinGW dependencies.
  • Make sure all required .dll files are bundled, especially when GTK+ requires multiple libraries.

By following these steps, you can successfully package your PyGObject/GTK+ app into a Windows executable that includes all necessary dependencies.