Bundle non-system libraries instead of version-pinning depends

Bundling R alone was not enough: R links libicuuc, and Arch moves ICU
regularly. The obvious fix - pinning 'icu>=78 <79' in depends - is worse
than the disease on a rolling distro, because pacman would then refuse to
upgrade ICU while JASP is installed, blocking the user's whole system
upgrade until a rebuild lands.

So bundle-libs.sh copies every non-system shared library into
/opt/jasp-desktop/lib and rewrites rpaths, by denylist rather than
allowlist. depends now carries no version constraints at all.

Qt6 stays system-provided on purpose - Qt is binary compatible across Qt 6
minors, and bundling QtWebEngine would add ~500 MB. That also means the
only rebuild triggers left are a new JASP release and a Qt major bump;
rebuilding for anything else would cost users a 1.7 GB re-download.

Also fixes check-upstream.py querying only repo=Extra, which silently
returned nothing for icu (it lives in core).
This commit is contained in:
agw
2026-09-01 22:05:00 +02:00
parent 7b39a5b06e
commit 56434ba7ed
7 changed files with 179 additions and 52 deletions
+25 -10
View File
@@ -30,14 +30,28 @@ does (`.github/workflows/ubuntu.yml` sets `JASP_R_VERSION: 4.5.3` and an explici
`R_HOME`). `Tools/CMake/R.cmake` reads `R_HOME` from the environment on Linux, so
this is a supported configuration rather than a hack.
Consequences:
## What is bundled, and why nothing is version-pinned
1. `r` is **not** a dependency of the package. An Arch R upgrade cannot break an
installed JASP.
2. What the binary is still linked against is Qt6 and ICU, both of which break ABI
across releases. The generated PKGBUILD pins those
(`qt6-base>=6.11 <6.12`, `icu>=78 <79`), and `scripts/check-upstream.py`
triggers a rebuild when Arch moves either — or when JASP releases.
After staging, `build/bundle-libs.sh` walks every ELF object in the tree, copies
each non-system shared library it depends on into `/opt/jasp-desktop/lib`, and
rewrites the rpath to look there. It works by *denylist*: glibc, libstdc++, Qt6,
the GL/X11/Wayland/dbus stack, fontconfig and freetype stay system-provided;
everything else — ICU, jsoncpp, glpk, JAGS, readstat, librdata, BLAS/LAPACK,
pcre2, readline — is bundled.
The point is that **`depends` contains no version constraints at all**. That is a
deliberate reversal of the obvious design. Pinning (`icu>=78 <79`) looks safer but
is actively harmful on a rolling distro: when Arch ships the next ICU, pacman
would refuse to upgrade it while JASP is installed, blocking the user's entire
system upgrade until a rebuild lands. Bundling means JASP never constrains the
system, and a `pacman -Syu` cannot break it.
Qt6 is the deliberate exception and stays a system dependency. Qt guarantees
binary compatibility across Qt 6 minor releases, and bundling QtWebEngine would
add ~500 MB for very little gain. A Qt 7 transition will need a rebuild — which is
why `scripts/check-upstream.py` watches the Qt *major* and nothing else besides
the JASP version. Rebuilding for anything else would cost every user a ~1.7 GB
re-download for no benefit.
`jags` and `librdata-git` are AUR-only, and JASP needs `freexl >= 2.0.99` while Arch
ships 2.0.0 — so the build compiles those itself, matching what upstream CI does.
@@ -47,7 +61,8 @@ ships 2.0.0 — so the build compiles those itself, matching what upstream CI do
| Path | Purpose |
| --- | --- |
| `build/build-jasp.sh` | The actual build. Runs in an `archlinux:base-devel` container, emits the tarball plus `build-info.json`. |
| `scripts/check-upstream.py` | Compares upstream JASP / Arch Qt6 / Arch ICU against `state.json`; decides whether to build. |
| `build/bundle-libs.sh` | Copies non-system shared libraries into `/opt/jasp-desktop/lib` and rewrites rpaths, so the package needs no version-pinned deps. |
| `scripts/check-upstream.py` | Compares upstream JASP and the Arch Qt major against `state.json`; decides whether to build. |
| `scripts/gen-pkgbuild.py` | Fills `packaging/PKGBUILD.in` from `build-info.json`; derives `pkgrel` from what is on the AUR. |
| `scripts/publish-github-release.sh` | Creates the GitHub release and uploads the tarball. |
| `scripts/push-aur.sh` | Generates `.SRCINFO` and pushes to `aur.archlinux.org`. |
@@ -59,10 +74,10 @@ ships 2.0.0 — so the build compiles those itself, matching what upstream CI do
```
nightly (03:00) ─► check-upstream.py
│ new JASP tag, or Arch bumped qt6-base / icu?
│ new JASP tag, or a Qt major transition?
▼
build-jasp.sh (Arch container, hours)
│ builds R 4.5.3, JASP, then all R modules
│ builds R 4.5.3, JASP, all R modules, then bundles libs
│ jasp-desktop-<ver>-x86_64.tar.zst + build-info.json
▼
GitHub release ──► gen-pkgbuild.py ──► push to AUR