Building Outer Wonders for Linux
utopixel.games
utopixel.games
I also have a Rust game, and I packaged it in a flatpak here (https://github.com/JMS55/sandbox/tree/master/flatpak). The main thing you want to look at is the .json manifest. The flatpak-cargo-generator.py script on the flatpak github takes a Cargo.lock, and outputs another flatpak manifest of third party dependency download links, so you don't need arbitrary internet access to build (a requirement for distributing on flathub), but you can ignore this if you're using itch.io.
Given that they were wrangling about not requiring an external libSDL dependency, it's unlikely they'll want to require an external flatpak dependency.
Flatpak is "We use the flatpak format, if you don't already have it, go to https://flatpak.org/setup/ and press your distro icon". Much more user friendly, and the hope is that flatpak becomes the standard way to distribute linux apps in the future anyways. Fedora already preinstalls flatpak, hopefully ubuntu and debian will follow (although that's unlikely since ubuntu has snap).
Locally, you could use vagrant to startup multiple linux distros then build and startup the game for a visual test. It would then be easier to output a list of "tested on platform/distro X,Y,Z" as well as the deps for each of them.
Also, you have to keep them up to date as new distro versions are released, whereas many games work on a principle of "release, and done".
Making a release where you link as much as you can statically increases the chances it will work in the future.
AppImage is a great option: it's the equivalent of statically linking everything. Users only need to have the binary and they can run it. Developers bundle everything into that binary.
Snap uses a compressed image format that makes startup horrid. And snaps don't seem to work well with hidpi resolutions when scaling is enabled (snap doesnt know about the scaling so it draws everything super small).
I haven't used AppImage but between apt, snap, and flatpak, I really see flatpak as the winner for how games should be installed.
It was a nice learning experience, but far from the "Easy to make, runs everywhere" marketing Appimages have.
Does using muls libc and statically linking everything actually work out in practice? I read somewhere (HN comment, don't have reference) that it still might not be enough and your programs still need to the OS libc.
it's not like it is esoteric knowledge though: https://docs.appimage.org/reference/best-practices.html#bina...
You can't use their dependencies or you'd need to provide builds for different versions of the same distro (because many many many libraries aren't that stable, and distros typically only provide one version of each).
And you probably don't want to run your own repository (and I'm not even sure apt can do repositories with a login, so you'd be making your game available to everyone with the link), so you can't use their update functionality either.
So then all you have left is a bad archive format - essentially a distro-specific .zip that's more annoying to build.
The other tools ship dependencies with the program, so they don't have this particular issue. AppImage and Flatpak are also cross-distro, while snap is tied to Canonical and awkward on other distros.
But this isn't an open source game, as far as I can see, and most games aren't.
Also I often find the fixed releases of most distros to be a bad fit for games because the stability argument matters less and less - there's little in the way of backward compatibility to keep, and hence no real reason not to upgrade.
(not that I'm much of a believer in fixed releases to begin with)
Distros are usually tied to specific versions of libraries. Your package can't require a library that is too old or too new, because the distro won't have that version, or won't install it, because it'd conflict with other packages. The way around it is to prefer static linking, but then you're reducing the whole dependency and packaging system to just being a zip file with extra steps.
There are many package formats, and many distros with different versions. It's a PITA to set up a build farm for everything and keep it from bitrotting.
And even if you build a two dozen packages, you need to help users download the right version, and tell them how to install it (my pet peeve in many distros is that when you double-click a deb/rpm, they won't offer to install it, but browse it like a folder or treat as an unknown file).
All of this is so much more fuss than "Here's your Windows.exe, or Mac Universal.app".
docker - we do exactly this for a non-game app at $WORK - building an app in some ancient centos or something docker image.
Yes, we do that at $dayjob too. We support multiple versions of CentOS, Debian and Ubuntu, and the best way to build for all of them is inside their respective Docker containers. We depend on libssl and that lets us use the platform's default libssl instead of forcing 1.0 on everything.
Also, as to patchelf, does it require an absolute path? If yes, are they patching post-download? I doubt they would somehow try to force Linux or the user to always put the binary in the same abs path, right?
Then you can use `objdump -d` to disassemble and see the callers. The fact that the binary is build from Rust isn't relevant at this point.
patchelf is passed a special string, '$ORIGIN', which references the same directory as the binary, and won't require modifications for the target system.
One disadvantage not mentioned in the blog post is that this facilitates something similar to the infamous DLL preloading attacks on Windows.
So if you make a game engine maybe you can try detecting this issue and warn the developer(and maybe ask to automatically fix it)
I don't think the first option is that much of a hurdle for Linux users. I guess there might be package conflicts that aren't trivial to resolve sometimes, but I'm not sure how often those pop up in the game dev scene, though.
I wonder if it would be viable for games to come with an AppImage (or one of the other two), and something like `game_assets.dat` for the game files (so the AppImage doesn't grow too large).
Also, slightly unrelated, but I think it would be make sense for ich.io to have a steam-like client for automating the game's life cycle on player machines. It would make it convenient for both devs and players. Maybe it could it could come with a set of tools for developers too to help automate some of the packaging/publishing woes.
They do! https://itch.io/app. It's even open source: https://github.com/itchio/itch.
> Maybe it could it could come with a set of tools for developers too to help automate some of the packaging/publishing woes.
They do have those as well! https://itch.io/docs/butler/
Technically it's shipped with the client so it does come with a set of tools.
...why don't all libraries work that way?
And TBH i'd rather games just assume SDL or is available and have it part of the system requirements (they already have other software requirements anyway), perhaps with a tiny launcher that tries to load the library dynamically and if fails it reports a more user friendly error. Most gamers on Linux will have it installed anyway since they'd be either launching from Steam (which bundles it as part of its own runtime) or also have other games installed.
(sadly SDL2 breaking ABI backward compatibility with SDL1 puts a wrench to that idea, which is why personally instead of using SDL2 i just write my own code - e.g. SDL2 fullscreen mode doesn't work in many window managers)
SDL_DYNAMIC_API=/my/actual/libSDL-2.0.so.0 ./MyGameThatIsStaticallyLinkedToSDL2
https://github.com/libsdl-org/SDL/blob/main/docs/README-dyna...I think many developers don't know about static libraries. For some reason they think they have to use a shared libraries. This is probably due to many tutorial saying something like: download the SDL2 library from there, it is provided as a shared library, here the instructions to use it with Visual Studio.
The way I do is with static libraries, I ship a single executable, all the third-party libraries are linked in as static libraries. The only dynamic libraries the exectuable will use are the standard libraries that are part of the OS.
I do this very easily with the help for lhelper:
https://github.com/franko/lhelper (I am the author)
that has recipes to build many libraries including SDL2. It builds the library on you system using your compiler and your settings. By default it will build static libraries so you don't have to bother distributing additional dynamic libraries.
How do you handle Steam or the user updating SDL2 to a newer version, then (see the sibling comments about dynapi)? Does your game depend on those tricks to run?
Criticism of the NPM / Node ecosystem aside (leftpad, etc) - this is a great reminder of a lesson I should be including when mentoring other devs: never hesitate to dig into a dependency, figure out how it works, and even rewrite it yourself if/when it makes sense. Removing the "magic" of libraries and dependencies is a really enlightening moment for new developers!
Yep, it's worth noting that the vast majority of closed source games I've encountered on Linux are static linked. For what it's worth (as a big proponent of dynamic linking and the maintainer model) I think that's totally fine. I wish there were no closed source applications to begin with, but if there have to be these programs, the process necessarily bypasses the model of maintainer quality control and patching. Games are supposed to be very long lived anyway, once they're past the initial period of getting regular bug fixes.
This is a hard requirement if your application uses OpenGL or Vulkan, you can't really statically link those libraries at all, and you have to use dlopen/dlsym to check each individual function in order to support extensions.
Last I checked, you could install Debian from a set of CDs which got regular point releases. Having something with decent power like a Core 2 Quad you could go back to around 2007 I guess (though I fear at this point they might have problems with their API). How do they solve the problem of running on Windows XP?
I suspect it's similar to how building a C++ project works. In Visual Studio you select the minimum version you want to support and you're done. This in general is a pain point of Linux - the toolchain is set up for building the system itself rather than producing binaries for general distribution and there is no easy way to set up a generic toolchain for a given basic version of libraries. This is great for letting you modify your system, but it's not ideal for software development.
Installing an old distro via docker or in a chroot works, but I wish I could have just a compiler plus libc rather than an entire Ubuntu. I think Redhat allows something like that, but it should be more widespread.
In this case, wouldn’t bundling everything be more stable?
It’s notoriously difficult to install some very old software on modern Linux distributions, because installing old dependencies might just be extremely hard or no longer possible.
Also, what happens when the glibc has a new version with breaking changes? Then the game won’t run, even though it depends on an old version of that lib.
In my opinion, the best way to ensure your game will run on the majority of Linux distributions, now and in the future, is to distribute a Windows binary and rely on WINE (or use winelib). Just make sure to actually test it.
For example, if you wanted to make your program use the "realpath" version from glibc 2.0, instead of the current one, you could do something like this:
__asm__(".symver realpath,realpath@GLIBC_2.0");
So, even if the glibc version in the build system is more modern (lets say 2.3), your code will also work with older ones, such as 2.0.
> In this case, wouldn’t bundling everything be more stable?
It might; or it might not. Relying on shared libraries is generally a good idea, as those get updated: for instance, you can get pulseaudio, wayland and more modern joysticks API compatibility by updating SDL.
However, some libraries cease development. This will not happen for SDL or glibc, as those have too many users, there will always be a compat layer. Plus, their source is available to actually create such a layer. It's a good idea to ship those libraries, but I sure hope they rely on shared libraries for system calls or hardware access.
As a bonus, relying on shared objects makes it easier to run something on other CPU architectures using a native build of the libraries, at least in theory.
(Nebukadnezzar recommended using Proton, which worked fine.)
https://stackoverflow.com/questions/57476533/why-is-statical...
But... They could have used a different libc, like musl which is designed for static linking.
Linux OSes are not designed to run binaries downloaded from the web like this and that's intentional.
I'm sure this is an unpopular opinion in these circles, but unless you're doing game development for the programming side of things, I just can't see how it would be worth all the hoops you'd have to jump through when there's an open, pretty performant, 100% cross-platform runtime-and-graphics-toolkit, just sitting there waiting to be used.
Native is guaranteed to work minus driver bugs, but it works nonetheless.
WebGL is dependent on the whims of the browser version and the set of blacklisted platforms, GPGPUs and drivers.
Then no matter how good the graphics card is, it will never go beyond OpenGL ES 3.0 capabilities minus a set of "dangerous" features.
It is no wonder that indie development moved away from Web based games into mobile platforms, after Web community managed to kill Flash.
For reference, OpenGL ES 3.0 was released in 2012.
In what concerns WebGPU, the first draft was just released, and it will be basically a kind of MVP when it gets finalized.
Then expect it to take as long as WebAssembly is taking to move beyond MVP 1.0.