Bundle our own R 4.5.3 instead of building against Arch's R

Arch ships R 4.6.1, but JASP pins its R packages against a frozen CRAN
snapshot (2026-03-31 for 0.98.1) that targets R 4.5. Configuring against
Arch's R fails at Rcpp 1.1.1, which cannot compile on R 4.6 since
R_NamespaceRegistry was removed; the Rcpp release that fixes it is newer
than the pinned snapshot, so the lockfile cannot reach it either.

Build R 4.5.3 into /opt/jasp-desktop/R and point R_HOME at it, matching
what upstream CI does. This drops 'r' from depends entirely, so an Arch R
upgrade can no longer break an installed JASP, and the rebuild triggers
become Qt6 and ICU - the libraries actually still linked against.
This commit is contained in:
agw
2026-09-01 21:40:00 +02:00
parent 3ad88f9b0d
commit d880e6748c
7 changed files with 130 additions and 64 deletions
+27 -14
View File
@@ -14,19 +14,30 @@ users download the result.
## The constraint that shapes everything
JASP does **not** bundle R or Qt6 on Linux. `Tools/CMake/R.cmake` only fetches
`R.framework` on macOS; on Linux JASP links against the distribution's R and Qt6,
and the R module library it ships is compiled against one specific R minor version.
JASP pins its R package set with renv lockfiles against a **frozen CRAN snapshot**
— for 0.98.1, `Modules/Rcpp_RInside.lock` points at the Posit snapshot of
2026-03-31. That set targets R 4.5.
A binary is therefore only valid for the R minor and Qt6 minor it was built
against. Two consequences:
Building against Arch's current R (4.6.1) fails immediately: Rcpp 1.1.1 does not
compile there, because `R_NamespaceRegistry` is gone in R 4.6. The Rcpp release
that fixes this (1.1.2, 2026-07-05) is *newer than the pinned snapshot*, so the
lockfile cannot resolve it either. This is precisely the "old libraries with
issues" problem that makes the source AUR package painful.
1. A rebuild is triggered by a new JASP release **or** by Arch bumping `r` or
`qt6-base`. `scripts/check-upstream.py` checks all three.
2. The generated PKGBUILD pins `depends` to those versions
(`r>=4.6 r<4.7`, `qt6-base>=6.11 qt6-base<6.12`). If Arch moves ahead before a
rebuild lands, pacman refuses the combination rather than leaving users with a
JASP that fails to start.
So this build **compiles and bundles its own R 4.5.3** into
`/opt/jasp-desktop/R` and points `R_HOME` at it — which is what upstream's own CI
does (`.github/workflows/ubuntu.yml` sets `JASP_R_VERSION: 4.5.3` and an explicit
`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:
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.
`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.
@@ -36,7 +47,7 @@ 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 R / Arch Qt6 against `state.json`; decides whether to build. |
| `scripts/check-upstream.py` | Compares upstream JASP / Arch Qt6 / Arch ICU 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`. |
@@ -48,9 +59,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 r / qt6-base?
│ new JASP tag, or Arch bumped qt6-base / icu?
▼
build-jasp.sh (Arch container, hours)
│ builds R 4.5.3, JASP, then all R modules
│ jasp-desktop-<ver>-x86_64.tar.zst + build-info.json
▼
GitHub release ──► gen-pkgbuild.py ──► push to AUR
@@ -90,7 +102,8 @@ The build runs for hours and needs disk. On the Gitea runner host:
time (set to `16h`).
- Gitea's own job timeout (`[actions] ENDLESS_TASK_TIMEOUT` in `app.ini`, default
3h) must match, otherwise Gitea kills the job at 3h regardless of the runner.
- Roughly 40–60 GB of free disk for the build tree and staged install.
- Roughly 40–60 GB of free disk for the build tree, the bundled R and the
staged install.
## Running it by hand