Is it really any linux?

May 12, 2026 ยท View on GitHub

Here is Cromite running in NixOS without any FHS-wrapper image
Here is Cromite running in Ubuntu 14.04 image
Here is WINE running foobar2000 in Ubuntu 14.04 image
Here is QEMU running in Ubuntu 12.04 image
Here is aarch64 Trelby running on 32-bit ARM debian ๐Ÿ‘€ This is possible because this system had a 64bit kernel and CPU, We do not depend on the host userland besides a shell in /bin/sh image

How come this only became possible in 2024?

  • For application to be truly portable we need to ship our own dynamic linker (ld-linux.so).
  • It turns out it is not possible to have a relative dynamic linker with executables.
  • polyfill glibc attempted to fix this issue with a experimental tool that replaces PT_INTERP with PT_LOAD and have the payload look for the relative dynamic linker but this never got finished.
  • We can execute the dynamic linker first and then pass the binary to launch to bypass this limitation, go-appimage had been doing this since ~2019.
  • But that runs into isues with /proc/self/exe.
  • sharun had to be made to fix the /proc/self/exe issues. And as far as I know, brioche had been using the same approach before sharun as well.
  • Once all the pieces were ready, the next step was changing the way we deploy AppImages and sorting all the bugs that came with that, AppImage was originally made with the idea of relying on the host glibc and a set of libraries that always had to come from the host.

Why bundle glibc instead of musl?

  • Using musl would mean any hardware accelerated application will not work with the proprietary nvidia driver.
  • musl runs into performance issues because the default allocator is not great, this even affected the type2 AppImage runtime.
  • It does not really save space, the libc is a small fraction of the entire AppImage size, the reason distros like alpine linux are small is because they optimize most of their packages for size like this example that results in a libicudata.so that is less than 1 MiB in size while most other distros do not bother to do this optimization and ship a 30 MiB libicudata.so. Many of these optimizations are already used in the debloated packages repo.
  • With glibc, we are able to dlopen optional libraries on the host even when those link to musl. If we used musl the opposite is usually not possible as musl lacks a lot of symbols that libraries expect from glibc. For example here is the Qt6-demo dlopening alpine's GTK3 to use the GTK3 platform theme and look native on the system:
image

We only use musl where it is very useful, that is when making static binaries.

Why not statically link everything?

  • That is super hard, some libraries are not meant to be statically linked as well and that means a ton of patches are needed.
  • Statically linking everything means we are not able to dlopen any library from the host, even optional ones like the example I just gave about dlopening the host GTK from Qt apps to follow the system theme.
  • It means goodbye to the proprietary nvidia driver.
  • It means you are no longer able use vulkan layers like mangohud or lsfg-vk.
  • It means you are forever stuck with the version of MESA that was statically linked. Remember with you can use the host Mesa if needed by setting SHARUN_ALLOW_SYS_VKICD=1 and that is something you will want to do if you plan on using the same AppImage for several years in the future.
  • Static linking some dependencies is still desired however, as that reduces the final size of the AppImage, but a fully static binary is a very bad idea.

Why DwarFS instead of SquashFS?

DwarFS is a lot faster than SquashFS while being smaller at the same time.

Screenshot_2026-04-27_02-09-36

DwarFS also offers PGO like optimizations, which allows us to make small appimages that start instantly.

AppImage has no thumbnail?

Because we use DwarFS instead of SquashFS, you need an AppImage thumbnailer that supports DwarFS:

Why is there no usr directory in the AppImages?

Because it causes more issues than it solves.

  • /usr is the typical installation prefix for an application.

  • $APPDIR/usr makes no sense, it just causes projects to code exceptions for appimage that do something alone these lines: getenv(APPDIR) + usr + xyz. Instead we make APPDIR the installation prefix directly. This means we can take any application and patch away the /usr prefix for $APPDIR and make them portable without the need for projects to support AppImage. Here are some examples where projects checking for $APPDIR just made things worse: 1 2

  • NOTE: $APPDIR/shared is the a internal directory that sharun uses for itself, you should never copy anything manually there.