Playing games with runtime extensions

One of the core ideas of xdg-app is that users should be running the same build of everything that the developers tested on. Not only does this mean that you can trust the testing that went into the app, but it also means that an app can run on multiple distributions, and on different version of the same distribution.

However, an application does not have bundle everything. Instead the app specifies a dependency on a runtime, which contains the base system libraries. I like to compare this to dynamic libraries, where xdg-app is “dynamically linked” to its runtime, whereas container systems (like docker) are “statically linked” (by shipping a complete runtime in each app).

This may seem weird and contrary to the first paragraph, but it turns out that this is pretty much a requirement. We want third parties to be able to produce a binary that will keep running “forever”, but the base system may need fixes or support for new hardware. We can’t expect every vendor to rebuild every application (for example some old game) each time something needs fixing on the lower levels. So, therefore we allow updates to the runtime separately from the app (although any update must be compatible).

An app can only depend on one runtime, and everything not in the runtime must be bundled with the application. There is (by design) no way to depend on multiple runtimes, or have runtimes depend on each other. However, there is something called runtime extensions. Extensions are a way to split off and make optional parts of the runtime and recombine them at runtime.

For instance, I’m working on a runtime called org.freedesktop.Platform that has the basic freedesktop libraries (X11, Mesa, DBus, etc). It has this snippet in the configuration:

[Extension org.freedesktop.Platform.Timezones]
directory=share/zoneinfo

This means that whenever another runtime called org.freedesktop.Platform.Timezones is installed its contents will replace the directory share/zoneinfo in the runtime. This is very useful as it allows the timezone info (which changes frequently) to be updated separately from the runtime.

It also has this:

[Extension org.freedesktop.Platform.Locale]
directory=share/runtime/locale
subdirectories=true

This means that if a runtime like org.freedesktop.Platform.Locale.sv is installed, it will replace the contents of share/runtime/locale/sv in the runtime. During the build all the locale data and translations are separated out into per-language runtimes which can be installed separately.

And finally, it has:

[Extension org.freedesktop.Platform.GL]
directory=lib/GL

There is no (official) runtime with this name, but if one is installed it will appear in lib/GL, and the main runtime has been programmed to look into this directory for libGL.

The idea here is that if your system uses an OpenGL driver that does not ship with the regular runtime (i.e. Mesa), or needs a more recent version of it, then you can create your own runtime with this name and get your drivers into the runtime.

For a long time this has been a theoretical solution, but recently I acquired an NVidia card in order to test this. The result is this script, which takes an upstream nvidia driver release and converts it into a runtime that matches the (soon to be released) 1.2 version of the Freedesktop runtime.

To verify that it works I created an xdg-app bundle for the Unreal Editor. Here are some screenshots of a sandboxed version of unreal to show this working:

Launching the unreal editor
Launching the unreal editor
Editing the sample project
Editing the sample project

While runtimes can’t have dependencies on other runtimes, they can be build from the same base, and thus be compatible. For instance, the official Gnome runtime takes the Freedesktop runtime and adds the Gnome modules to it. Since we have the same ABIĀ  we can reuse the same extensions. The two runtimes have different versions (Gnome is 3.18, Freedesktop is 1.2), so we have to specify the version (which is otherwise infered by the runtime version). Here is how the Gnome runtime config looks:

[Extension org.freedesktop.Platform.GL]
version=1.2
directory=lib/GL

I hope to have stable builds out of the Freedesktop 1.2 and Gnome 3.18 runtimes shortly, so that other people can play with them. Unfortunately I’m not allowed to distribute the unreal editor app.

2 thoughts on “Playing games with runtime extensions”

  1. just curious, how come runtimes cannot depend on runtimes?

    wouldn’t this make whole thing even less dependent on distribution as you’d only need lower layers to be native?

    btw, would be awesome if this Unreal work somehow got to Epic as right now there is no launcher and only way to get it is in source and compile

    1. someone:
      Runtimes depending on runtimes has two problems.

      First, as a matter of practicallity, you have to combine the layers somehow. Any such combination method risks running into complications when the layers change independently. For instance a security update in the base layer could be overridden by some middle layer having its own version of the library. It also means things that derive from the base layer at build time, such as icon caches and whatnot will not work, or will have to be made more complicated by adding rpm/deb like post-install scripts.

      Secondly, and more fundamentally, it reproduces the packaging model of rpm and deb, where what actual users are running is made much more complicated and hard to predict. I believe a more robust and predictable model of what exact bits of software is running will lead to a higher quality result.

      That said, on the *build* side you can indeed have runtimes depend on runtimes. In fact, the gnome runtime does depend on the freedesktop runtime in this sense. It just happens before being shipped to the user. And, throught the magic deduplication that ostree (which xdg-app uses) this does not actually lead to larger downloads/diskspace use/memory use. Sweet, eh?

Leave a Reply

Your email address will not be published. Required fields are marked *