Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 20 additions & 13 deletions docs/astro/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -182,19 +182,26 @@ export default defineConfig({
label: "Platforms",
collapsed: true,
items: [
"guide/platforms/desktop",
"guide/platforms/embedded",
{
label: "Mobile",
collapsed: true,
items: [
"guide/platforms/mobile/general",
"guide/platforms/mobile/android",
"guide/platforms/mobile/ios",
],
},
"guide/platforms/web",
"guide/platforms/other",
"guide/platforms/desktop",
{
label: "Packaging",
collapsed: true,
items: [
"guide/platforms/packaging/linux-packaging",
],
},
"guide/platforms/embedded",
{
label: "Mobile",
collapsed: true,
items: [
"guide/platforms/mobile/general",
"guide/platforms/mobile/android",
"guide/platforms/mobile/ios",
],
},
"guide/platforms/web",
"guide/platforms/other",
],
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
---
title: Linux
description: Package a desktop Slint app for distribution on Linux, using Flatpak
---

{/* cSpell: ignore Flatpaks yourorganization pulseaudio jpegd jpege Metainfo metainfo Flathub launchable */}

import { Aside } from '@astrojs/starlight/components';
import { Tabs, TabItem } from '@astrojs/starlight/components';

Linux, unlike other platforms, has countless ways to distribute applications. Each of these has its own pros and cons, different supported distros, etc. For this article, we will focus on [Flatpak](https://flatpak.org/). Here is an incomplete list of the alternatives, with the reason that we think they are less well-suited to our purposes here than Flatpak:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we're in the guide section, I don't think it's really necessary to justify our choice of Flatpak. A short reference to the alternatives is fine IMO. We're not competing with anyone here :)


- Distro-native package managers (`pacman`, `apt`, `dnf`, etc)
- Requires building and testing your application on many different systems, in particular different versions of host packages such as glibc
- [Snap](https://snapcraft.io/)
- Tied to the Canonical ecosystem, usually the best option when distributing a GUI application for Ubuntu and derivatives but far less popular on other distros
- [AppImage](https://appimage.org/)
- Less well-supported than Snap and Flatpak, the runtime is not shared between applications so the package size is larger compared to Flatpak and Snap. Additionally, AppImage does not provide sandboxing. Since Slint applications can run seamlessly inside Flatpak/Snap's sandbox, so the increased security of a sandbox doesn't require any tradeoff

Flatpaks are sandboxed, cross-platform, and they are relatively straightforward to create.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a positive key phrase :)


<Aside type="note">
Your application may come with different trade-offs, and so you may want to make another choice.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be the box where you could very briefly mention alternatives IMO.

</Aside>

## Prerequisites

The tools needed are the `flatpak` and `flatpak-builder` tools. Additionally, depending on language, you may need a tool which converts your package manager's lockfile into a set of dependencies that `flatpak-builder` understands. The Flatpak build process is sandboxed, just like Flatpaks themselves, and any tools running inside the build environment do not have network access. Any dependencies that need to be downloaded via the network need to be specified in the Flatpak dependency format.
Comment thread
eira-fransham marked this conversation as resolved.
Outdated

Lockfile conversion scripts are available for all languages supported by Slint:
Comment thread
eira-fransham marked this conversation as resolved.
Outdated

- Rust
- [`cargo`](https://github.com/flatpak/flatpak-builder-tools/tree/master/cargo)
- NodeJS
- [`node`](https://github.com/flatpak/flatpak-builder-tools/tree/master/node) - this is the recommended method, supporting `npm`, `yarn` and `pnpm`
- [`npm`](https://github.com/flatpak/flatpak-builder-tools/tree/master/npm) (if the `node` script does not work)
- [`yarn`](https://github.com/flatpak/flatpak-builder-tools/tree/master/yarn) (if the `node` script does not work)
- Deno
- [`deno`](https://github.com/flatpak/flatpak-builder-tools/tree/master/deno)
- Python
- [`pip`](https://github.com/flatpak/flatpak-builder-tools/tree/master/pip)
- [`poetry`](https://github.com/flatpak/flatpak-builder-tools/tree/master/poetry)

C++ has no standard, cross-platform package manager, and for C++ projects the only officially-supported method of including dependencies is via vendoring. Bun is supported by Slint, but not by Flatpak.

## Creating a build file

Flatpak build files are named after the package ID. For most projects, the package ID will be `com.yourorganization.YourProject`. For this example, we'll use `com.slint.TestPackage`, meaning that the build script will be named `com.slint.TestPackage.yml`.

```yaml
# The ID, explained above.
id: com.slint.TestPackage

# The "runtime" to use. For desktop applications, this will almost always be
# `org.freedesktop.Platform`
Comment on lines +57 to +58

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there's doubt, then I think there's value in explaining it. Otherwise, I think it's better to just state the fact to avoid leaving the reader hanging. Here, I'd just stick to org.freedesktop.Platform and that's it.

A comment on the version might be more relevant, perhaps with a link where readers can find out what versions exists and if it's worth upgrading.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This remains an open point.

runtime: org.freedesktop.Platform
runtime-version: "25.08"

# This will be explained below
command: slint-test-package

# The "sdk" to use. Again, this will almost always be `org.freedesktop.Sdk`
sdk: org.freedesktop.Sdk

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also needed this:

sdk-extensions:
  - org.freedesktop.Sdk.Extension.rust-stable

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I meant to mention that below in the Rust section. Good catch.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought, don't we always need this? For C++ we surely do. For Python and Node.js what's in this template is incomplete.


# The set of permissions that this application requires
finish-args:
# OpenGL/Vulkan rendering
- --device=dri
# Allow use of IPC (required by Wayland and X11)
- --share=ipc
# Allow using Wayland via the Freedesktop sandbox protocol extensions
- --socket=wayland
# Use X11 as a fallback. There is also `--socket=x11` for applications
# that require X11, but `--socket=fallback-x11` overrides it
- --socket=fallback-x11
```

The permissions specified above are the minimum required for all Slint applications, but in case you require further permissions you can check [Flatpak's official documentation](https://docs.flatpak.org/en/latest/sandbox-permissions.html). Notable permissions are `--share=network` for network access, `--socket=pulseaudio` for audio I/O, and `--allow=bluetooth` for Bluetooth connectivity.

## Specifying the build process

Along with the basic metadata, you will then need to specify your dependencies and build process. This will depend on the language used.

<Tabs syncKey="dev-language">
<TabItem label="Rust" icon="seti:rust">

First, you need to run the [`flatpak-cargo-generator.py`](https://github.com/flatpak/flatpak-builder-tools/tree/master/cargo) script, mentioned above. This will create a file named `cargo-sources.json`.

```yaml
modules:
# The module name is arbitrary, but Flatpak will create a `/run/build/your-module-name`
# directory and build the package inside of it, so it should match any `/run/build/..`
# paths in the build config. It does not need to match the command name.
- name: slint-test-package
# This tells Flatpak that you will be writing the build commands out manually, in
# `build-commands` (see below)
buildsystem: simple
build-options:
# This adds the Rust SDK to your PATH
append-path: /usr/lib/sdk/rust-stable/bin
env:
# Required to keep the Cargo build artifacts inside Flatpak's sandboxed build
# directory
CARGO_HOME: /run/build/slint-test-package/cargo
CARGO_NET_OFFLINE: "true"
# This is required for Slint's Skia backend, and should match the source below.
# With the FemtoVG backend, you can remove this line and the relevant source.
SKIA_BINARIES_URL: file:///run/build/slint-visual-editor/deps/vendor/skia/skia-binaries-a25a0fdb7d90429aa2d1-x86_64-unknown-linux-gnu-gl-jpegd-jpege-pdf-textlayout-vulkan.tar.gz

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This refers to the visual editor. Subsequent for all the skia related bits, I strongly suggest to leave those out of these instructions for now. There's value in supporting Skia here, but I think that could almost go into a separate section.

That said, it's in our interest to support Skia (for our own needs), and for Linux then alternative that I think is easier to support, without the need to hard-code URLs like the above), is to build skia from sources. I think automating that will be easier because instead of the user having to figure out skia-binaries-a25a0fdb7d90429... type of URLs, we can use the existing meta-data in skia-bindings to determine the correct url for the source sources and prepare that.

I tried a local build with skia sources (by setting SKIA_SOURCE_DIR) and that works within the sandbox.

So I see three paths forward:

  1. We keep the above as it is. I'd prefer not, because it'll be outdated by the time we release Slint 1.18.
  2. We omit skia from the instructions for now and I'll try to create a separate PR to add a section and a helper script for apps that would like to include it and then the build will build it from source.
  3. I'll try to finish my experiment with from-source build and we incorporate it in this PR.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My preferred path would be 3, although personally I think this is fine. I give instructions on how to figure out which URL to include.

Not that you're suggesting this, but I definitely don't think that leaving it out is an option since Skia is the best-supported renderer. All of those options are viable though, I wouldn't be unhappy with any of them.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've included my instructions, so you get to choose :)

build-commands:
- cargo --offline fetch --manifest-path Cargo.toml --verbose
# For the sake of this example, we assume that this build command produces a binary
# named `slint-test-package`. If you do not need the Skia renderer, you can use
# `--features backend-winit,renderer-femtovg` and remove the lines related to Skia
# binaries
- cargo build --release --offline --features backend-winit,renderer-skia
Comment thread
tronical marked this conversation as resolved.
Outdated
# The right-hand side of this must be `${FLATPAK_DEST}/bin/your-command`, where
# `your-command` matches the top-level `command` field mentioned in the previous
# section
- install -Dm0755 target/release/slint-test-package ${FLATPAK_DEST}/bin/slint-test-package
sources:
- type: git
# This assumes that this yaml file is in the root of your project. This may not
# be what you want, see below for some other options.
path: ./
# This should be the current git commit hash, or the git commit hash that you
# want to build
commit: 1234deadbeef
# If you named your generated sources file something different, or put it somewhere
# other than in the same directory as this file, you should specify the path to it
# here
- cargo-sources.json
# The below lines (and the `SKIA_BINARIES_URL` environment variable, specified above)
# are required to use the `renderer-skia` feature. If your application uses
# `renderer-femtovg`, you can remove it
- type: file
url: https://github.com/rust-skia/skia-binaries/releases/download/0.99.0/skia-binaries-a25a0fdb7d90429aa2d1-x86_64-unknown-linux-gnu-gl-jpegd-jpege-pdf-textlayout-vulkan.tar.gz
dest: deps/vendor/skia
sha256: 097e78d775c9156dc4b070b9cca7008dbab587513ecb1924baf4cf9620f3119b
```

As mentioned in the comments above, to use `renderer-skia` you must include the relevant Skia binaries as an explicit dependency. At the time of writing, this is `0.99.0`. You can use the following command to check the version of `skia-safe` in use (requires `jq` to be installed):

```bash
cargo metadata --format-version 1 | jq -er '.packages | .[] | select(.name == "skia-safe").version'
```

If this is not `0.99.0`, check [the releases page](https://github.com/rust-skia/skia-binaries/tags) for `rust-skia/skia-binaries`, finding the one that has the `x86_64-unknown-linux-gnu` target triple and the `gl-jpegd-jpege-pdf-textlayout-vulkan` feature set. You can also copy the hash and put it in the `sha256` field, mentioned above.

</TabItem>
</Tabs>

## Icons and desktop metadata

To ensure that your application shows up in the launcher, you need to create a `.desktop` file, along with an icon file. In our case, this will look like so:
Comment thread
eira-fransham marked this conversation as resolved.
Outdated

```ini
[Desktop Entry]
Encoding=UTF-8
Version=1.0
Type=Application
Terminal=false
# This should be the same as the binary specified in the `command` section
# of your build `.yaml`
Exec=/app/bin/slint-test-package
# This should be the human-readable name of your application
Name=Slint Test Package
# This should be the same as your Flatpak package ID, see below for details
Icon=com.slint.TestPackage
```

You then need to add a command that puts this in the correct place to your `build-commands`, like so:
Comment thread
tronical marked this conversation as resolved.

```yaml
# ...
build-commands:
# ...
- install -Dm0644 path/to/${FLATPAK_ID}.desktop ${FLATPAK_DEST}/share/applications/${FLATPAK_ID}.desktop
# ...
```

For the icon, you have a few options. Flatpak will search the following folders (here specified as you would in the build script):

- `.png` files in `${FLATPAK_DEST}/share/icons/hicolor/WIDTHxHEIGHT/apps/`, where `WIDTHxHEIGHT` matches the width and height of your image (up to 512)
- `.svg` files in `${FLATPAK_DEST}/share/icons/hicolor/scalable/apps/`

Whether your choose `.png` or `.svg`, the file should be named the same as your Flatpak package ID, and you should add an `install` command to `build-commands` that outputs the file to the correct directory, with the same name as your Flatpak package ID. For example:

```yaml
# ...
build-commands:
# ...
# Replace 512x512 with the width and height of your icon
- install -Dm0644 path/to/icon.png ${FLATPAK_DEST}/share/icons/hicolor/512x512/apps/${FLATPAK_ID}.png
# ..or...
- install -Dm0644 path/to/icon.svg ${FLATPAK_DEST}/share/icons/hicolor/scalable/apps/${FLATPAK_ID}.svg
# ...
```

## Metainfo

Finally, Flatpak expects your package to include a `.metainfo.xml` file, which specifies some Flatpak-specific metadata used by the package manager and by Flathub. The [full specification of this file](https://docs.flathub.org/docs/for-app-authors/metainfo-guidelines) is out of scope for this document, but below is the minimum required fields that must be specified in order for validation to succeed:

```xml
<?xml version="1.0" encoding="UTF-8" ?>
<component type="desktop-application">
<id>com.slint.TestPackage</id>

<name>Slint Test Package</name>
<summary>Example package to explain how to create a Flatpak for a Slint project</summary>

<categories>
<category>Development</category>
</categories>

<keywords>
<keyword>development</keyword>
</keywords>

<developer id="com.slint">
<name>Slint</name>
</developer>

<icon type="stock">com.slint.TestPackage</icon>

<metadata_license>MIT</metadata_license>
<project_license>MIT</project_license>

<description>
<p>Example package to explain how to create a Flatpak for a Slint project</p>
</description>

<url type="homepage">https://slint.dev/</url>

<launchable
type="desktop-id"
>com.slint.TestPackage</launchable>

<screenshots>
<!--
Flathub requires at least one screenshot, but an empty screenshot section
is allowed when building locally.
-->
</screenshots>

<releases>
<release version="1.0" date="2026-07-07">
<description translatable="no">
</description>
</release>
</releases>
</component>
```

## Putting it all together

The build `.yaml` was specified in fragments, so below is a complete example package manifest with the annotations removed, that you can copy and modify for your own project.

<Tabs syncKey="dev-language">
<TabItem label="Rust" icon="seti:rust">

```yaml
id: com.slint.TestPackage

runtime: org.freedesktop.Platform
runtime-version: "25.08"

command: slint-test-package

sdk: org.freedesktop.Sdk

finish-args:
- --device=dri
- --share=ipc
- --socket=wayland
- --socket=fallback-x11

modules:
- name: slint-test-package
buildsystem: simple
build-options:
append-path: /usr/lib/sdk/rust-stable/bin
env:
CARGO_HOME: /run/build/slint-test-package/cargo
CARGO_NET_OFFLINE: "true"
SKIA_BINARIES_URL: file:///run/build/slint-visual-editor/deps/vendor/skia/skia-binaries-a25a0fdb7d90429aa2d1-x86_64-unknown-linux-gnu-gl-jpegd-jpege-pdf-textlayout-vulkan.tar.gz
build-commands:
- cargo --offline fetch --manifest-path Cargo.toml --verbose
- cargo build --release --offline --features backend-winit,renderer-skia
- install -Dm0755 target/release/slint-test-package ${FLATPAK_DEST}/bin/slint-test-package
sources:
- type: git
path: ./
commit: 1234deadbeef
- cargo-sources.json
- type: file
url: https://github.com/rust-skia/skia-binaries/releases/download/0.99.0/skia-binaries-a25a0fdb7d90429aa2d1-x86_64-unknown-linux-gnu-gl-jpegd-jpege-pdf-textlayout-vulkan.tar.gz
dest: deps/vendor/skia
sha256: 097e78d775c9156dc4b070b9cca7008dbab587513ecb1924baf4cf9620f3119b
```

</TabItem>
</Tabs>