Multiarch support¶
Flatpak has multiarch/multilib support, but it’s not enabled by default and require some additional steps to enable it. This section covers enabling multiarch/multilib in your application bundle.
Running 32-bit programs¶
In order to set up the run time environment for 32-bit executables, first you’ll
need to allow it in finish-args
:
finish-args:
- --allow=multiarch
This is enough for static binaries, but most real-world GNU/Linux programs are linked dynamically. Those need some shared libraries to work.
Freedesktop.org and GNOME SDKs both provide a special flatpak extension with a set of libraries for corresponding architecture. This extension can be attached to an app of different architecture. In order to enable the extension for your app, define an extension point for it in the app manifest:
add-extensions:
org.freedesktop.Platform.Compat.i386:
directory: lib/i386-linux-gnu
version: '23.08'
# This is not strictly required, but needed for debugging 32-bit programs
org.freedesktop.Platform.Compat.i386.Debug:
directory: lib/debug/lib/i386-linux-gnu
version: '23.08'
no-autodownload: true
For GNOME runtime, use org.gnome.Platform.Compat.i386
instead.
Note that this extension version
must match the runtime-version
of the
application.
If the 32-bit programs make use of GPU acceleration, or have some graphical UI in general, you’ll also need 32-bit GL drivers. Add an extension point for it:
runtime: org.freedesktop.Platform
runtime-version: &runtime-version '23.08'
# Synced from Freedesktop runtime
# https://gitlab.com/freedesktop-sdk/freedesktop-sdk/-/blob/ed97d222b21d0a8744779ce6e5e8af5b032bfee1/elements/flatpak-images/include/platform-vars.yml#L2
x-gl-version: &gl-version '1.4'
x-gl-versions: &gl-versions 23.08;1.4
x-gl-merge-dirs: &gl-merge-dirs vulkan/icd.d;glvnd/egl_vendor.d;egl/egl_external_platform.d;OpenCL/vendors;lib/dri;lib/d3d;lib/gbm;vulkan/explicit_layer.d;vulkan/implicit_layer.d
org.freedesktop.Platform.GL32:
directory: lib/i386-linux-gnu/GL
version: *gl-version
versions: *gl-versions
subdirectories: true
no-autodownload: true
autodelete: false
add-ld-path: lib
merge-dirs: *gl-merge-dirs
download-if: active-gl-driver
enable-if: active-gl-driver
autoprune-unless: active-gl-driver
org.freedesktop.Platform.GL32.Debug:
directory: lib/debug/lib/i386-linux-gnu/GL
version: *gl-version
versions: *gl-versions
subdirectories: true
no-autodownload: true
merge-dirs: *gl-merge-dirs
enable-if: active-gl-driver
autoprune-unless: active-gl-driver
org.freedesktop.Platform.VAAPI.Intel.i386:
directory: lib/i386-linux-gnu/dri/intel-vaapi-driver
version: *runtime-version
versions: *runtime-version
autodelete: false
no-autodownload: true
add-ld-path: lib
download-if: have-intel-gpu
autoprune-unless: have-intel-gpu
Note that the x-gl-versions
property here must contain both 1.4
and the same value as in runtime-version
.
Make sure to create directories where the extensions will be mounted (the mount
points are specified in directory
properties and are relative to the app
bundle mount point, i.e. to /app/
). This can be done at stage of the build.
Finally, you need to make the dynamic library loader know the paths to 32-bit
libraries. In order to do this, you can install a /app/etc/ld.so.conf
file
with contents like this:
/app/lib32
/app/lib/i386-linux-gnu
Here /app/lib32
is the directory where you install additional 32-bit
libraries, if any.
You can combine the above two steps in a special module, e.g.
modules:
- name: bundle-setup
buildsystem: simple
build-commands:
- mkdir -p /app/lib/i386-linux-gnu
- mkdir -p /app/lib/debug/lib/i386-linux-gnu
- mkdir -p /app/lib/i386-linux-gnu/GL
- mkdir -p /app/lib/i386-linux-gnu/dri/intel-vaapi-driver
- install -Dm644 ld.so.conf /app/etc/ld.so.conf
sources:
- type: inline
dest-filename: ld.so.conf
contents: |
/app/lib32
/app/lib/i386-linux-gnu
Building 32-bit modules¶
The section above describes how to run 32-bit programs that are already built. This section will describe the process of building 32-bit components yourself to ship them with the application. It assumes that you are already familiar with building (single-arch) flatpaks. If not, please refer to Flatpak Builder guide first.
First of all, you’ll need to enable some SDK extensions at build time:
sdk-extensions:
- org.freedesktop.Sdk.Compat.i386
- org.freedesktop.Sdk.Extension.toolchain-i386
The first one is the 32-bit portion of the SDK, containing 32-bit libraries and development files.
The second one is a cross-compiler. Usually gcc -m32
is used for multilib
builds, but the flatpak SDK comes with gcc without multilib support. Thus, you
will need a cross-compiler for building x86 on x86_64 just as you would need it
for any foreign architecture like aarch64.
In order to build a 32-bit module, some global build options needs to be
overridden. Examples here assume that 32-bit libraries are installed in
/app/lib32
directory:
modules:
- name: some-lib-32bit
build-options: &compat-i386-build-options
# Make sure 32-bit dependencies are first on pkg-config search path
prepend-pkg-config-path: /app/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig
# Add /app/lib32 to linker search path for modules without pkg-config
ldflags: -L/app/lib32
# Add the cross-compiler to PATH
prepend-path: /usr/lib/sdk/toolchain-i386/bin
# Tell the build systems to use the cross-compiler for compilation
env:
CC: i686-unknown-linux-gnu-gcc
CXX: i686-unknown-linux-gnu-g++
# Tell the build systems to install libraries to /app/lib32
libdir: /app/lib32
These build-options
need to be set for each 32-bit module. If your app
manifest is in YAML format, the YAML anchors can come in handy and save you from
copy-pasting the same snippet. You can define the 32-bit build-options
object somewhere in the manifest, add an anchor to it, and then point each
32-bit modules‘ build-options
to that anchor:
x-compat-i386-build-options: &compat-i386-build-options
prepend-pkg-config-path: /app/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig
ldflags: -L/app/lib32
prepend-path: /usr/lib/sdk/toolchain-i386/bin
env:
CC: i686-unknown-linux-gnu-gcc
CXX: i686-unknown-linux-gnu-g++
libdir: /app/lib32
modules:
- name: some-lib-32bit
build-options: *compat-i386-build-options
- name: some-other-lib-32bit
build-options: *compat-i386-build-options
Of course, in order to actually use 32-bit modules you’ve build, you’ll also need all the same setup from the previous section.