Hello, Flatpak! A better* guide
This is a very simple and abridged guide for making Flatpak packages, with special focus towards developers without much packaging experience. This guide was also written from the complaints a friend and I had towards the existing introduction section of the Flatpak Documentation, which seems to skip over some things I deemed important.
This guide will assume you already have a working project on some git repository. The one used here will be based around this basic demo program.
This guide also assumes you have flatpak and flatpak-builder already installed, which are already available on most package managers.
1. Installing the SDK
Flatpak has "Platforms" or "Runtimes", which are a set of common libraries you link against. It also has the concept of SDKs which are a bunch of development files you might need to properly build your programs, such as headers and compilers.
In this example, we'll use the Freedesktop 22.08 Runtime and SDK:
flatpak install flathub org.freedesktop.Platform//22.08 org.freedesktop.Sdk//22.08
It contains all sorts of useful things (like SDL2 which is necessary for the provided demo program.) You can check what it includes here. There's also a couple more runtimes you probably should use if your program uses GTK or QT.
If you dont find the previous library list complete enough, you can check out the FAQ for some juicy valuable information around this ;)
2. Writing a manifest
Manifests are just files that specify what your program is, what it needs and how to build it. They can be written in JSON and YAML, but I'll be using JSON for this particular example.
> 1. Setting things up
Create a new folder, then a JSON file named as RDNN notation of your project, I'll be going with io.github.darltrash.demo.json.
It has to contain something like:
{
"id": "io.github.darltrash.demo",
"runtime": "org.freedesktop.Platform",
"runtime-version": "22.08",
"sdk": "org.freedesktop.Sdk"
}
id:The RDNN notation for your projectruntime:The runtime we're going to useruntime-version:The runtime version we're going to usesdk:The SDK we're going to use for building
This will be our manifest.
> 2. Container permissions
Flatpak works with containers, which allow for programs to be sandboxed and benefit the user, but they require developers to handle the resources and explicitly tell Flatpak what host resources will their programs use.
Lets take a look at this snippet:
"finish-args": [
"--device=dri",
"--socket=x11",
"--socket=wayland",
"--share=ipc"
]
finish-args are just explicit definitions for container settings, just a way of telling the container to unlock certain things for the program to work properly.
--device=driwill give us explicit and direct GPU access, there's also other modes you can use to access other devices--socket=x11grants us the ability to talk to X11 (Legacy graphics), you can also use--socket=fallback-x11to use X11 only when Wayland isn't present--socket=waylandgrants us the ability to talk to Wayland compositors (graphics)--share=ipcallows us to talk to the rest of the OS through IPC but it also allows us to use some X11 extensions to allow better performance
There's some other permissions we can use, as provided here.
We will add this to our manifest and it should be enough for purely graphical, hardware accelerated programs.
> 3. Actually building the thing 👍
The Flatpak build system works with modules, which are simple build and setup instructions, for either your software or necessary dependencies.
We'll define our main module like this:
"modules": [
{
"name": "demo",
"buildsystem": "simple",
"sources": [
{
"type": "git",
"url": "https://github.com/darltrash/sdl2-demo",
"commit": "766db3652802e69fa8b8e33a42f5f30efcca37e6"
}
],
"build-commands": [
"make release",
"install -D demo /app/bin/demo"
]
}
]
name:The name for the current module being built.buildsystem:The build system for the module.sources:A list of sources to be used for building.build-commands:Regular shell commands to build the module.
Now, I wont go into too much detail about the available build systems, nor the available source types, but can check them out here.
We're using the "simple" build system as it allows us to simply just tell the Flatpak builder to execute certain commands inside an isolated environment.
build-commands, in this example, contains two commands:
make releasewhich compiles the program as release, change this to whatever you needinstall -D demo /app/bin/demowill copy the output compiled program (demo) to/app/bin, which mirrors/usr/binhere in Flatpak-land
3. Running!
Now I'll one last line to my manifest file:
"command": "demo"
This will tell Flatpak to execute /app/bin/demo as the entry point for our program.
Now to actually build and run this thing, we need to run this:
flatpak-builder --user --install build-dir/ io.github.darltrash.demo.json --force-clean
flatpak run io.github.darltrash.demo
I'll go over those spooky commands and try to explain them:
flatpak-builder --user --install build-dir/ io.github.darltrash.demo.json --force-clean: Builds the project into a new folder namedbuild-dir/and installs it user-wide, using the manifestio.github.darltrash.demo.json. You might also want to add--ccacheif your program is primarily reliant in C(++)flatpak run io.github.darltrash.demo: FINALLY, this runs the project!
If everything goes right, it should display a funky (and buggy) DVD screen-saver thing!! (trust me, the bugginess is because of my sheer incompetence towards creating basic demo examples...)
But... this project is missing something really important! It's missing a .desktop file, which means that our program will NOT show up on the programs menu, So we'll make one!
Create a new file, next to our manifest, named like io.github.darltrash.demo.desktop, like our manifest but with the .desktop extension instead, and make it look something like this:
[Desktop Entry]
Name=Flatpak Demo
Comment=A simple Flatpak demo.
Exec=demo
Type=Application
There's much more you can do with a .desktop file (ex. have icons) but I wont go too in depth for that, you can check the spec here.
Now we'll change our manifest's main module to include our new file and "install" it in it's right place.
"sources": [
...
{
"type": "file",
"path": "io.github.darltrash.demo.desktop"
}
],
"build-commands": [
...
"install -D io.github.darltrash.demo.desktop /app/share/applications/io.github.darltrash.demo.desktop"
]
/app/share/applications/ (analog to /usr/share/applications) being a folder that contains .desktop files that must be shown in the form of programs to the user, in their programs menu.
And there we have it! Now a program named "Flatpak Demo" should show up on your program menu!
4. Meet the .flatpak file!
.flatpak files (Also called Single File Bundles) are similar to what a zipped program would be in Windows, except that Flatpak gets to handle all the rough details, like dependencies and installation
.flatpak files are nice because they are:
- Portable (for the most part)
- Simple to understand for users who have Flatpak installed and set up
- Compatible, in the same way that Android APKs and MacOS .apps are compatible
Now, let's make one!
flatpak-builder --user --install build-dir/ io.github.darltrash.demo.json --force-clean
flatpak build-export export/ build-dir/
flatpak build-bundle export/ our-file.flatpak io.github.darltrash.demo
Let's go over some of those commands:
flatpak-builder --user --install build-dir/ io.github.darltrash.demo.json --force-cleanBuilds our project once moreflatpak build-export export/ build-dir/Stores the build/install procedure's whole output into a new folder namedexport/flatpak build-bundle export/ our-file.flatpak io.github.darltrash.demoturns those useful files into an actual package file namedour-file.flatpak
Now you should have a file named our-file.flatpak which you can install like:
flatpak install our-file.flatpak
or by using a GUI Flatpak client, such as Gnome Software which comes preinstalled in all major GNOME-based distros, such as Ubuntu and Fedora.
And that's it! We've done it! Now you can share this .flatpak file anywhere you want; through email, an instant chat messenger, on an USB drive, some game publishing platform, by pigeon, you name it!
If you're interested on reading more about Single File Bundles, check out the official documentation.
I've published all this cool stuff in a repo, here, so you can check it out by yourself :)
FAQ:
Can I make the manifest just build local files?
Yes! In the same way you pulled the .desktop file, you can pull an entire folder if necessary, You would only need to add something like this to your sources:
{
"type": "dir",
"path": "whatever/directory/you/like"
}
TIP: If your local file or directory is an archive, you can replace type by archive instead of dir so Flatpak can handle the decompression for you.
This is only advised for local development, Because Flathub will require your manifest to have it's own repository, as they will need to clone it for them to be able to publish it.
Can I use an URL instead of a GIT repository?
Yes! You can include something like this in your sources:
{
"type": "file",
"url": "https://whatever.weird.url.you.have.com/",
"sha256": "766db3652802e69fa8b8e33a42f5f30efcca37e6"
}
Which will download whatever file is at URL, and check it's checksum.
The sha256 part is necessary to ensure that the file being obtained is 100% legitimate, you can also use sha1 or sha512.
TIP: Again, you can also get it to download and automatically decompress archives, by replacing type by archive instead of file.
How can I get a more detailed list of what's inside the SDK?
You will need to install it first, then you'll have to run this command
flatpak info -l org.freedesktop.Sdk//22.08
It will give you the exact location of all the files that our SDK contains, you can change the SDK by anything you'd like, this also works for Platforms, Runtimes, Applications, you name it!
Inside of said folder, you'll find a folder aptly named files which contains a semi-traditional linux filesystem structure, specifically mimicking /usr/.
Can my entry point be a script that runs something else?
Yes, easily, you can add something like this to your sources:
{
"type": "script",
"commands": [
"/app/bin/your_program --here"
],
"dest-filename": "your_entry_point_here"
}
commandsis a list of commands that your entry point script will executedest-filenameis meant to be your destination filename, in this case, you want this to match up with thecommandproperty
You can also just include a simple script as a file, and set that as your entry point.
TIP: Remember that your .desktop file will have to reflect this!
Why doesn't my program show up in the programs menu, but runs in the terminal?
A big possible reason is that you have a malformed .desktop file, where it either has the wrong setup and/or syntax, or it's trying to call your entry point incorrectly (or straight up calling something else); In that case, try out desktop-file-validate.
Another reason is that you did not put the file where it belongs, which is /app/share/applications/ and not /usr/share/applications since Flatpak replaces /usr with /app.
SDL2 won't work because it needs pulseaudio or something like that?:
That's because SDL2 by default also has an audio module that uses the Pulseaudio protocol, you can add the following to your finish-args:
"--socket=pulseaudio"
This will enable Pulseaudio on your program's container/sandbox, and thus, also Pipewire.
I recommend also checking out the other options if you have any other issues with either devices or necessary permissions not being granted.
How can I publish my programs on Flathub?
Sadly, I haven't written that part yet! But you can check the official documentation for that.
If you found this guide valuable on it's contents, you might be interested on a posible guide coming for that in the future! (No promises, though.)
Thanks for reading! ✨
I hope this has helped you! because I wrote this document purely because I also tried to make a Flatpak package once, and I only found disdain and suffering.
Huge thanks to the following people:
- Newbyte: Professional nerd who has helped me better understand Flatpak and Linux in general
- shakesoda: For giving me an agnostic angle at writing this document.
- Landon: for being chill asf
- And everyone else for the valuable feedback!
(Please, do not contact those people online, they have their own problems lol)