Skip to main content
Version: 11.0.x

Debian / Ubuntu packaging

Avalonia Linux programs can be executed in most Linux distros by double-clicking the executable or by starting it from the terminal. Nevertheless, for a better user experience, it is recommended to have the program installed, so the user can start it via desktop shortcut, that exists in desktop environments such as GNOME and KDE, or via command-line, by having the program added to PATH.

Debian and Ubuntu related distros have their applications packaged in .deb files, that can be installed via sudo apt install ./your_package.deb.

Tutorial

In this tutorial, we will use the dpkg-deb tool to compile your .deb package.

1) Organize program files in a staging folder

Debian packages follow this basic structure:

./staging_folder/
├── DEBIAN
│   └── control # package control file
└── usr
├── bin
│   └── myprogram # starter script
├── lib
│   └── myprogram
│   ├── libHarfBuzzSharp.so # Avalonia native library
│   ├── libSkiaSharp.so # Avalonia native library
│   ├── other_native_library_1.so
│   ├── myprogram_executable # main executable
│   ├── myprogram.dll
│   ├── my_other_dll.dll
│   ├── ... # all files from dotnet publish
└── share
├── applications
│   └── MyProgram.desktop # desktop shortcut file
├── icons
│   └── hicolor
│   ├── ... # other resolution icons (optional)
└── pixmaps
└── myprogram.png # main application icon

Meaning of each folder:

  • DEBIAN: contains the control file.
  • /usr/bin/: contains the starter script (recommended for starting your program via command-line).
  • /usr/lib/myprogram/: where all files generated by dotnet publish go into.
  • /usr/share/applications/: folder for the desktop shortcut.
  • /usr/share/pixmaps/ and /usr/share/icons/hicolor/**: folders for application icons.
info

The /usr/share/icons/hicolor/** are optional, as in your app icon will probably show up on desktop even without those images, however, it is recommended to have them for better resolution.

2) Make the control file

The control file goes inside the DEBIAN folder.

This file describes general aspects of your program, such as its name, version, category, dependencies, maintainer, processor architecture and licenses. Debian docs have a more thorough description of all possible fields in the file.

Author's comment

Don't worry too much about filling all possible fields, most aren't required. This tutorial is to make a "good-enough" Debian package.

The .NET dependencies can be listed by running apt show dotnet-runtime-deps-8.0 (suffix changes for other .NET versions); they will appear on the line starting with Depends: .... Avalonia required dependencies are: libx11-6, libice6, libsm6, libfontconfig1. Overall, all .NET and Avalonia dependencies are required, plus any others specific of your app.

Below is a simple example of a control file.

Package: myprogram
Version: 3.1.0
Section: devel
Priority: optional
Architecture: amd64
Installed-Size: 68279
Depends: libx11-6, libice6, libsm6, libfontconfig1, ca-certificates, tzdata, libc6, libgcc1, libgssapi-krb5-2, libstdc++6, zlib1g, libssl1.0.0 | libssl1.0.2 | libssl1.1 | libssl3, libicu | libicu72 | libicu71 | libicu70 | libicu69 | libicu68 | libicu67 | libicu66 | libicu65 | libicu63 | libicu60 | libicu57 | libicu55 | libicu52
Maintainer: Ken Lee <kenlee@outlook.com>
Homepage: https://github.com/kenlee/myprogram
Description: This is MyProgram, great for doing X.
Copyright: 2022-2024 Ken Lee <kenlee@outlook.com>

3) Make the starter script

This step is recommended for two reasons: first, to reduce the complexity of the desktop shortcut, and second, to make your app runnable from Terminal.

The starter script file name should preferrably be myprogram (without .sh extension), so whenever your user types "myprogram" on the Terminal, he / she will start your program.

The myprogram_executable file usually has the same name as its .NET project, e.g., if your Avalonia .csproj project is named MyProgram.Desktop, then the main executable generated by dotnet publish will be MyProgram.Desktop.

Example of starter script:

#!/bin/bash
# use exec to not have the wrapper script staying as a separate process
# "$@" to pass command line arguments to the app
exec /usr/lib/myprogram/myprogram_executable "$@"

4) Make the desktop shortcut

The desktop shortcut file follows the freedesktop specification. Arch Linux Wiki also has good related information.

Below is an example of a desktop shortcut file.

[Desktop Entry]
Name=MyProgram
Comment=MyProgram, great for doing X
Icon=myprogram
Exec=myprogram
StartupWMClass=myprogram
Terminal=false
Type=Application
Categories=Development
GenericName=MyProgram
Keywords=keyword1; keyword2; keyword3
tip

If your app is supposed to open files, append %F at the end of the Exec line, after myprogram; if it's supposed to open URLs, then append %U.

5) Add hicolor icons (optional)

Hicolor icons follow a folder structure like below.

This blog post advises us to put icons on both hicolor and pixmaps directories, according to Debian Menu System docs and FreeDesktop docs.

├── icons
│   └── hicolor
│   ├── 128x128
│   │   └── apps
│   │   └── myprogram.png
│   ├── 16x16
│   │   └── apps
│   │   └── myprogram.png
│   ├── 256x256
│   │   └── apps
│   │   └── myprogram.png
│   ├── 32x32
│   │   └── apps
│   │   └── myprogram.png
│   ├── 48x48
│   │   └── apps
│   │   └── myprogram.png
│   ├── 512x512
│   │   └── apps
│   │   └── myprogram.png
│   ├── 64x64
│   │   └── apps
│   │   └── myprogram.png
│   └── scalable
│   └── apps
│   └── myprogram.svg

6) Compile the .deb package

# for x64 architectures, the suggested suffix is amd64.
dpkg-deb --root-owner-group --build ./staging_folder/ "./myprogram_${versionName}_amd64.deb"

Example of a Linux shell script for the entire process

#!/bin/bash

# Clean-up
rm -rf ./out/
rm -rf ./staging_folder/

# .NET publish
# self-contained is recommended, so final users won't need to install .NET
dotnet publish "./src/MyProgram.Desktop/MyProgram.Desktop.csproj" \
--verbosity quiet \
--nologo \
--configuration Release \
--self-contained true \
--runtime linux-x64 \
--output "./out/linux-x64"

# Staging directory
mkdir staging_folder

# Debian control file
mkdir ./staging_folder/DEBIAN
cp ./src/MyProgram.Desktop.Debian/control ./staging_folder/DEBIAN

# Starter script
mkdir ./staging_folder/usr
mkdir ./staging_folder/usr/bin
cp ./src/MyProgram.Desktop.Debian/myprogram.sh ./staging_folder/usr/bin/myprogram
chmod +x ./staging_folder/usr/bin/myprogram # set executable permissions to starter script

# Other files
mkdir ./staging_folder/usr/lib
mkdir ./staging_folder/usr/lib/myprogram
cp -f -a ./out/linux-x64/. ./staging_folder/usr/lib/myprogram/ # copies all files from publish dir
chmod -R a+rX ./staging_folder/usr/lib/myprogram/ # set read permissions to all files
chmod +x ./staging_folder/usr/lib/myprogram/myprogram_executable # set executable permissions to main executable

# Desktop shortcut
mkdir ./staging_folder/usr/share
mkdir ./staging_folder/usr/share/applications
cp ./src/MyProgram.Desktop.Debian/MyProgram.desktop ./staging_folder/usr/share/applications/MyProgram.desktop

# Desktop icon
# A 1024px x 1024px PNG, like VS Code uses for its icon
mkdir ./staging_folder/usr/share/pixmaps
cp ./src/MyProgram.Desktop.Debian/myprogram_icon_1024px.png ./staging_folder/usr/share/pixmaps/myprogram.png

# Hicolor icons
mkdir ./staging_folder/usr/share/icons
mkdir ./staging_folder/usr/share/icons/hicolor
mkdir ./staging_folder/usr/share/icons/hicolor/scalable
mkdir ./staging_folder/usr/share/icons/hicolor/scalable/apps
cp ./misc/myprogram_logo.svg ./staging_folder/usr/share/icons/hicolor/scalable/apps/myprogram.svg

# Make .deb file
dpkg-deb --root-owner-group --build ./staging_folder/ ./myprogram_3.1.0_amd64.deb

To install

sudo apt install ./myprogram_3.1.0_amd64.deb

To uninstall / remove

sudo apt remove myprogram

Third-party packaging tools for Debian / Ubuntu