Skip to content

Building on Linux

Wesley edited this page Aug 24, 2026 · 2 revisions

Building on Linux

Covers building, installing, running and debugging on Linux, and - at the bottom - producing Linux and macOS builds from a Windows machine.

The general prerequisites, project layout and test commands are on Building from source; this page only adds what is specific to these targets.

Commands are written as wails3 task <name>, which works as soon as the Wails CLI is installed because Task ships inside it. If you have installed Task on its own, task <name> is the same command.

Linux support is newer than the Windows build, and the platform catalog reflects that: Platforms.linux.json covers a smaller set than Platforms.json, and some platforms are deliberately hidden because their Windows detection has no Linux equivalent.

What the build links against

Wails v3 links GTK4 and WebKitGTK 6.0 on Linux (pkg/application/linux_cgo.go declares #cgo linux pkg-config: gtk4 webkitgtk-6.0). The GTK3 and WebKit2GTK 4.1 pair is a fallback behind a build tag, so installing those -dev packages for a default build achieves nothing.

Packages
Fedora, Bazzite, Silverblue gcc gcc-c++ pkgconf-pkg-config gtk4-devel webkitgtk6.0-devel libsoup3-devel glib2-devel
Debian, Ubuntu build-essential pkg-config libgtk-4-dev libwebkitgtk-6.0-dev libsoup-3.0-dev
Arch base-devel pkgconf gtk4 webkitgtk-6.0 libsoup3

At runtime a machine needs only the libraries themselves: libgtk-4, libwebkitgtk-6.0 and libsoup-3.0. The packages generated by wails3 task linux:package declare exactly those.

The build needs CGO, so it has to run on Linux. There is no GOOS=linux go build from Windows without a container - see Cross-compiling from Windows.

Immutable distributions

On rpm-ostree systems (Bazzite, Silverblue, Kinoite) put the toolchain in a container rather than layering it onto the host, which would cost a reboot for packages the running system does not need:

toolbox create -y -d fedora -r 44 devbox
toolbox run -c devbox sudo dnf install -y gcc gcc-c++ pkgconf-pkg-config gtk4-devel webkitgtk6.0-devel libsoup3-devel glib2-devel

Match -r to the host release (. /etc/os-release && echo "$VERSION_ID"). A toolbox shares $HOME with the host, so a binary built inside runs outside it, and a Go toolchain unpacked under ~/sdk is visible from both.

Build

cd frontend && pnpm install && cd ..
wails3 task linux:build

Output is bin/TcNo-Acc-Switcher. wails3 task linux:build builds natively when it is on Linux with a C compiler, and falls back to the Docker image otherwise.

Add ARCH=arm64 for a cross-architecture build; that always goes through Docker.

For a development build with hot reload, wails3 task dev.

Package

wails3 task linux:package

Writes an AppImage, a .deb, an .rpm and an Arch package into bin/. The packagers install:

Path From
/usr/local/bin/tcno-acc-switcher bin/TcNo-Acc-Switcher
/usr/share/applications/tcno-acc-switcher.desktop build/linux/desktop
/usr/share/icons/hicolor/*/apps/tcno-acc-switcher.png build/linux/icons/

Icon= in a desktop entry is a theme name, not a path, so the icon has to land in hicolor at sizes the theme declares - a single oversized PNG in one size directory is not found reliably.

Do not regenerate the desktop entry with wails3 generate .desktop. The maintained file at build/linux/desktop carries StartupWMClass=org.wails.tcno_account_switcher, and without it a Wayland compositor cannot match the window to the entry and draws its own placeholder icon instead. That value is the GtkApplication id Wails builds from the app name, which LinuxOptions.ProgramName cannot override; TestDesktopEntryMatchesWaylandAppID fails if the two drift apart.

Install

Install the package your distribution uses:

sudo apt install ./bin/tcno-acc-switcher_*.deb
sudo dnf install ./bin/tcno-acc-switcher-*.rpm

Or install the pieces by hand, which is the practical route on an immutable distribution. /usr/local there is a symlink to /var/usrlocal: writable, and it survives system updates.

sudo install -Dm755 bin/TcNo-Acc-Switcher /usr/local/bin/tcno-acc-switcher
sudo install -Dm644 build/linux/desktop /usr/local/share/applications/tcno-acc-switcher.desktop
sudo install -Dm644 build/linux/icons/256x256/apps/tcno-acc-switcher.png /usr/local/share/icons/hicolor/256x256/apps/tcno-acc-switcher.png
sudo update-desktop-database /usr/local/share/applications

The AppImage needs no install - mark it executable and run it.

Running

wails3 task linux:run

or run bin/TcNo-Acc-Switcher directly.

User data goes to ~/.config/TcNo Account Switcher/ (os.UserConfigDir), holding Settings/, LoginCache/, Logs/ and the rest. A folder named TcNo Account Switcher sitting beside the binary wins instead, which is how portable mode is detected - worth knowing if you run the binary out of bin/, since that folder is created there.

Confirm the machine has what the binary links against:

ldd bin/TcNo-Acc-Switcher | grep "not found"

Silence is a pass.

Debugging

DevTools are compiled out of release builds. -tags production disables them along with the context menu, so right-click-inspect and Ctrl+Shift+I only exist in a debug build - use wails3 task dev, or build without the production tag.

A window that is one flat colour and nothing else means the web page never rendered. The app retries the load once and then puts an error panel on screen naming what failed; if you get the bare colour instead, the boot watchdog itself did not load.

Logs. ~/.config/TcNo Account Switcher/Logs/TcNo-Acc-Switcher.log, with one rotated generation beside it as .1. Everything also goes to stderr, so a terminal launch shows it live. Raise the level with --log-level debug (debug, info, warn, error).

Environment knobs worth trying when the window renders wrongly rather than not at all:

Variable Why
WEBKIT_DISABLE_COMPOSITING_MODE=1 Black or blank webview on some GPU and driver combinations
WEBKIT_DISABLE_DMABUF_RENDERER=1 Same, on newer WebKitGTK under certain drivers
GDK_BACKEND=x11 Runs under XWayland instead of natively on Wayland, which separates compositor problems from app ones
G_MESSAGES_DEBUG=all GTK's own warnings

Killing a stuck instance. pkill and pgrep match /proc/<pid>/comm, which is capped at 15 characters, so tcno-acc-switcher matches nothing. Use the truncated name, and not -f:

pkill -x tcno-acc-switch

Window icon problems are almost always the desktop entry rather than the app: check that StartupWMClass still matches the Wayland app_id, and that the icon exists in hicolor under the name Icon= gives.

Cross-compiling from Windows

Both targets need CGO, so both go through the wails-cross Docker image: Debian bookworm with the GTK4, WebKitGTK 6.0 and GTK3 development packages, Zig, and the macOS SDK. Build it once, with Docker running:

wails3 task setup:docker

That is roughly an 800 MB download. The Taskfile mounts your Go module cache into the container, so the first build is the only slow one.

Linux from Windows

wails3 task linux:build

On a non-Linux host this routes to the Docker path automatically and leaves bin/TcNo-Acc-Switcher, an ELF binary. Build the frontend first if you have changed it - the binary embeds frontend/dist, and the container only builds it when that directory is missing, so stale assets ship silently:

cd frontend && pnpm run build && cd ..

Two things to know about the Docker path on Windows:

  • It shells out to id -u to hand ownership of bin/ back after the container writes as root. Git for Windows ships id.exe; if C:\Program Files\Git\usr\bin is not on your PATH the task fails at that step, after the binary has already been produced.
  • The container's glibc is 2.36, so the output runs on any distribution at least that new. Building on an older base than your target is the right direction; the reverse is not.

wails3 task linux:package cannot run from Windows - the packagers and AppImage tooling are Linux binaries. Build on Linux for anything you intend to distribute.

macOS from Windows

wails3 task darwin:build

Leaves bin/TcNo-Acc-Switcher built for macOS, arm64 by default. ARCH=amd64 selects Intel, and wails3 task darwin:build:universal produces one binary carrying both.

What this gives you is a bare Mach-O executable, not a .app bundle, and it is unsigned. Bundling, code signing and notarisation use Apple's own tooling and have to happen on macOS - a cross-built binary is for compiling and smoke-testing, not for shipping.

Clone this wiki locally