Trying to understand how to distribute a Python video-game

Hello,
I developed a video game that is based on Pygame. Now I would like to distribute my game as simply as possible (in a way that not only developers could run it :slight_smile: ), but I’m really having the worst time of my life trying to understand how Python packaging and distributing works, what is up to date, what should I use, etc.
For now I concentrate on Linux distribution, I didn’t event start to think about Windows (But it will come… ).
I’m totally confused with all documentations I read about :

  • source distributions
  • built distributions
  • setuptools
  • pip
  • wheels
  • eggs
  • PEP517 518 or whatever specifications
  • AppImages (this seems to be the better looking solution but I just didn’t find anything clear to help me understand how to wrap a Python app)
  • The problem of low level dependencies compiling like glibc.
  • setup.py or setup.cfg
  • pyproject.toml

There is too much coexisting things and I can’t figure out what is the logical choice to make.


My game project is structured in the following way:

It relies on a open source game engine module I created, based on Pygame, that I released as a Python package on Pypi: fantomatic-engine · PyPI
The engine does all the job. The actual game project just imports the engine and runs it with a variable to provide the location of the game assets.

my_game_project/
    |_ my_game/
        |_ __init__.py
        |_ __main__.py
        |_ data/
            |_ game config and assets...
# Locally I just run the game like this
# At this point everything is fine.
my_game_project $ python ./my_game

The __main__.py is really just the following:

from fantomatic_engine import run_game
import os
from pathlib import Path

os.environ["EXEC_DIR"] = str(Path(__file__).parent) # This is processed by the engine to find out where is the data diretory

if __name__ == "__main__":
    run_game()

And that’s it.


From there I’m trying to understand what should I do to just wrap this in some sort of standalone executable. I already tried a lot of thing but I always end up stuck …

I will not describe here all the things I already tried but I would really appreciate if someone could help me to find the right way of doing this.

Any help will be greatly appreciated.

Thank you very much !

1 Like

You should probably take a look at pyinstaller · PyPI

It’s likely you’ll still find a lot of stuff confusing (python packaging is not the easiest subject for beginners :slightly_frowning_face:) but a lot of things are to do with distributing libraries, and not relevant for your needs. If you start with the pyinstaller docs and learn what you need starting from there, you may find it easier to make progress.

Good luck!

This one item is different than the others :slight_smile:

Snap, Flatpak and AppImage are conceptually similar ways to bundle apps.
They have nothing specifically to do with Python packaging - they depend
on designating a specific runtime which executes your code, so in your
case you’d declare Python and all your dependencies in the manifest,
assuming those are not already part of the runtime, and a bundle is
built which is run with a single command, using that runtime. This also
isolates you from things like glibc differences, although those really
aren’t common anyway. I couldn’t begin to advise you which one of the
three to look at if you decide to go that route, there have been
numerous comparison articles posted on the internet

They’re pretty easy to build, see the example here:

https://docs.flatpak.org/en/latest/first-build.html

This won’t help you at all on Windows, it /may/ be possible to run one
or more of these under WSL (depending on what you need out of the
graphics system) but if you need Windows support eventually, you may as
well learn how to package in a more Python-specific manner.

Thanks for your answer @pf_moore
In fact I already gave a little try to Pyinstaller. It almost seemed a great solution but unfortunately it doesn’t include glibc in the bundle, and even by generating the executable on an old Linux with an old glibc version (like recommended in the docs), I was never able to get the right glibc/python version combination, and my executable only worked on the very same platform it had been built on… So I dropped the idea …

Thanks @mwichmann ,
I’ll give a try to the flatpak solution :).

Ah, bundling glibc (and/or handling compatibility of libraries like glibc) is mostly outside the scope of Python packaging. The “manylinux” machinery is how we ensure binary compatibility for libraries, but I don’t know how or if it translates to executables (I’m a Windows user, not a Linux user, personally). But I suspect that if you ask on the pyinstaller support forums, there will be someone who has experience with that problem and might be able to help you.

2 Likes

Finally I gave another chance to Pyinstaller that seems to do the best what I want.
I made a build on debian 11 with glibc2.31, and I have no problem running the executable on another system (Fedora33) with glibc2.32.
Hoping that this will do for the Linux distribution.
Now, go windows ^^.

Thanks for help :).

1 Like

For Windows you really just need to get all the files laid out in a directory that sits on its own and works (you can use the “embeddable Python” package for this - it’s why that package exists) and then copy that directory to the other computers.

There are a few tools that can help, though they all have weird places where they will break. Fundamentally though, anything that can extract files into a directory and make a shortcut for your users to click on will do.

1 Like

may be not the real answer you are looking for but may help to know something like this exist.

I’m not sure bundling glibc would even work. When Python is launched, it loads the system glibc. I don’t know whether the dynamic linker will load another glibc if it is instructed to load glibc again from another dynamic library with a different search path (or if it will “remember” the first glibc found) but I think that is going to cause trouble either way?

In manylinux, compatibility is achieved by simply building on old systems with old glibc versions.

Hello @peterrabbit !

This looks like an excellent match for PyEmpaq. If you pack it using PyEmpaq you will get a .pyz that can be run with the system’s Python and that’s all you need (not only for Linux but also for other platforms).

I can help you to create the configuration file for PyEmpaq. If I understand correctly you have a game that is using the fantomatic engine, right? Where can I access the files for that game?

Regards,