Skip to content

Building and Packaging

Velle Sinclair edited this page Aug 8, 2026 · 4 revisions

Building and Packaging

Every component lives in its own directory with its own PKGBUILD. There are two build paths: the inner loop (fast, for development) and the ISO pipeline (slow, for releases).

bash build-all.sh                  # inner loop: every component against llama-staging/usr/
sudo ./archiso/build.sh            # full ISO pipeline (see Cutting an ISO Release)

Prerequisites: an Arch host with archiso, base-devel, meson, ninja, wlroots0.20, scenefx0.5, quickshell, qemu, ovmf. Budget ~22 GB free with the embedded model, ~9 GB without.

scenefx is built and installed before synui, not alongside it — synui links libscenefx-0.5.so and the build is red without it. It is also a fork of wlroots' scene graph, vendored in scenefx/, so a wlroots bump is a port of two things, not one.


The version model (read this before you bump anything)

There are two versions and they are not the same thing.

Version Where Bump it?
iso_version archiso/profiledef.sh Yes — this is the release version
SYNAPSEOS_VERSION archiso/build.sh No. Leave it at 0.1.0.

SYNAPSEOS_VERSION is the package series. Most PKGBUILDs declare source=("<pkg>-0.1.0.tar.gz") literally, so if you bump it, build.sh's create_source_tarball emits <pkg>-0.1.1.tar.gz and every makepkg fails to find its source.

So packages are versioned 0.1.0-<pkgrel> and the ISO is 0.1.4. Ship a code change by bumping the component's pkgrel.

(build.sh's completion banner cosmetically prints SYNAPSEOS_VERSION=0.1.0. Harmless, left alone.)


The traps

These are all silent — they let a build "succeed" on the wrong code.

Always regenerate the source tarball

Most PKGBUILDs consume a tarball, not your working tree. Edit a .c, run makepkg without regenerating <pkg>-0.1.0.tar.gz, and you package the old code and exit 0. build-all.sh and build.sh each regenerate it — but if you run makepkg by hand, you must too.

The src/ collision hazard

Never rm -rf src/ inside a component directory (this bit us in synui/, and applies to synguard/ too). makepkg just recreates it, and the stale copy gets picked up again on the next run. Cleaning the source tree's src/ by hand does not help.

The related bug in the ISO pipeline: the temp-build cleanup removed only src/<pkg>-* (the tarball extraction dirs) and missed the versionless src/<pkg> that git-sourced packages (nexus-chat, tepris) extract to. That stale git working copy got copied into the synbuild area with .git alternates pointing back at your $HOME — unreadable by the unprivileged synbuild user — and makepkg aborted with "does not appear to be a git repository". Fixed by wiping the whole src/ in the temp copy.

Check for untracked source files before a release

synui/src/ctlpanel.c once sat untracked while meson.build already listed it. git commit -a would have pushed a tree that does not build. Before cutting a release:

git status --short --untracked=all -- synui synapd synguard synsh synnet synapse_kmod

Look for ?? on real source, not just modified files, and stage it explicitly.

Two copies of everything

Several things exist in more than one place and drift silently:

  • create_source_tarball exists twice — in build-all.sh and separately in archiso/build.sh. This one went wrong four times out of four: each fix landed in one collector and not the other, and the symptom every time was a file missing from the tarball and a build that failed later, somewhere else. Both now delegate to the component's own <pkg>/mktarball.sh when it has one, which is the deduplication — a component that knows which files it needs says so once, in its own directory. Prefer adding a mktarball.sh over teaching the collectors about your package.
  • Which components each collector builds is the same split, and it went wrong a fifth time: a package was named in archiso/build.sh (so every ISO carried it) and in build-all.sh's KNOWN= list — but never given a build rule in build-all.sh itself. Asking for it by name therefore passed the argument check, matched nothing, and exited 0 having built nothing, so installed systems could never update it while the ISO was fine. Adding a component means editing both collectors; build-all.sh now fails loudly if an argument it accepted was never dispatched.
  • Session environment variables live in three places: the live /usr/local/bin/synui-session, and two blocks in syn-install.sh.
  • foot.ini is generated in three places, with two different tokenizers.
  • chibi has three copies of every module.
  • The event-sound id chains exist twice: sound_event_ids() in synui/src/sound.c and ids() in synui-sound.sh. They must stay in lockstep — the C side decides what the panel displays, the shell side decides what actually plays, so a drift means the panel confidently names a sample you will never hear.

Package builds run as synbuild

Package builds run as the unprivileged synbuild user under /var/tmp, because makepkg must not run as root and must live outside /home (mode 0700, so synbuild can't read it).

A failed package build aborts the run immediately rather than resurfacing later as a confusing pacstrap error. That's deliberate — an earlier version let failures through and they showed up as "package not found" much later.


llama.cpp

Pinned at tag b8272, matching CI. The CUDA build needs a patch for CCCL 3.4 (cub). Verified clean with gcc 16 + nvcc 13.3.

--no-clean preserves archiso/build/llama.cpp so this doesn't get recompiled — it is by far the most expensive step. It is safe: build.sh always wipes mkarchiso's work/ and gates only build/ on --clean.


Shared git index hazard

Concurrent sessions working in ~/SYNAPSE share one git index. Never unstage files you didn't stage, and stage + commit atomically (git add <paths> && git commit) rather than staging and then doing other work.

See also: Cutting an ISO Release, Troubleshooting.

Clone this wiki locally