Upstream JASP ships no Linux binary, so the existing AUR package builds everything from source including several hundred R packages. This builds that once in CI and publishes the result as jasp-desktop-bin. JASP links against the system R and Qt6 rather than bundling them, so a rebuild is triggered by an Arch r/qt6-base bump as well as by a new JASP release, and the generated PKGBUILD pins depends to the versions actually built against.
186 lines
6.4 KiB
Bash
Executable File
186 lines
6.4 KiB
Bash
Executable File
#!/bin/bash
|
|
# Build JASP Desktop on Arch Linux and emit a relocatable binary tarball.
|
|
#
|
|
# Runs as root inside an `archlinux:base-devel` container. The resulting tarball
|
|
# is what the AUR `jasp-desktop-bin` package downloads and unpacks, so this
|
|
# script also records the exact versions of the Arch libraries JASP ends up
|
|
# linked against — the PKGBUILD pins `depends` to them.
|
|
#
|
|
# JASP_TAG upstream tag to build, e.g. v0.98.1 (required)
|
|
# OUT_DIR where the tarball + metadata land (default /work/out)
|
|
# JOBS compile parallelism (default nproc)
|
|
#
|
|
# JASP links against the distro's R and Qt6 rather than bundling them
|
|
# (Tools/CMake/R.cmake only fetches R.framework on macOS), so a build is only
|
|
# valid for the R minor and Qt6 minor present at build time.
|
|
|
|
set -euo pipefail
|
|
|
|
JASP_TAG="${JASP_TAG:?JASP_TAG is required, e.g. v0.98.1}"
|
|
OUT_DIR="${OUT_DIR:-/work/out}"
|
|
JOBS="${JOBS:-$(nproc)}"
|
|
|
|
SRC_DIR=/build/jasp-desktop
|
|
BUILD_DIR=/build/build
|
|
STAGE_DIR=/build/stage
|
|
PREFIX=/opt/jasp-desktop
|
|
|
|
mkdir -p "$OUT_DIR" /build
|
|
|
|
log() { echo ":: $* "; }
|
|
|
|
# ---------------------------------------------------------------- system deps
|
|
log "installing Arch dependencies"
|
|
pacman -Syu --noconfirm --needed \
|
|
base-devel git cmake ninja gcc gcc-fortran make pkgconf patchelf \
|
|
autoconf automake libtool bison flex gettext blas lapack ccache \
|
|
qt6-base qt6-declarative qt6-svg qt6-positioning qt6-webchannel \
|
|
qt6-webengine qt6-5compat qt6-shadertools qt6-websockets qt6-tools \
|
|
qt6-httpserver vulkan-headers \
|
|
boost boost-libs r glpk jsoncpp libarchive openssl curl sqlite zlib \
|
|
readstat netcdf mpfr cairo fontconfig harfbuzz fribidi \
|
|
libpng libtiff libjpeg-turbo minizip libxkbcommon libxkbcommon-x11 \
|
|
wget unzip
|
|
|
|
# Stock makepkg.conf leaves MAKEFLAGS at -j1, which makes the AUR dependencies
|
|
# (JAGS especially) crawl. R's Makeconf picks this up for module builds too.
|
|
sed -i "s|^#\?MAKEFLAGS=.*|MAKEFLAGS=\"-j${JOBS}\"|" /etc/makepkg.conf
|
|
export MAKEFLAGS="-j${JOBS}"
|
|
|
|
# makepkg refuses to run as root.
|
|
if ! id builder &>/dev/null; then
|
|
useradd -m builder
|
|
echo "builder ALL=(ALL) NOPASSWD: ALL" >/etc/sudoers.d/builder
|
|
fi
|
|
|
|
# jags and librdata are AUR-only; build them the same way a user would.
|
|
build_aur() {
|
|
local pkg="$1"
|
|
log "building AUR package $pkg"
|
|
sudo -u builder bash -euc "
|
|
cd /home/builder
|
|
rm -rf '$pkg'
|
|
git clone --depth 1 'https://aur.archlinux.org/$pkg.git'
|
|
cd '$pkg'
|
|
makepkg -si --noconfirm --needed
|
|
"
|
|
}
|
|
build_aur jags
|
|
build_aur librdata-git
|
|
|
|
# JASP requires freexl >= 2.0.99; Arch ships 2.0.0, so use upstream's own fork
|
|
# exactly as the JASP CI does.
|
|
log "building jasp-stats/freexl"
|
|
rm -rf /build/freexl
|
|
git clone --depth 1 https://github.com/jasp-stats/freexl.git /build/freexl
|
|
cd /build/freexl
|
|
./configure --prefix=/usr
|
|
make -j"$JOBS"
|
|
make install
|
|
|
|
# ------------------------------------------------------------------- checkout
|
|
log "cloning jasp-desktop $JASP_TAG"
|
|
rm -rf "$SRC_DIR"
|
|
git clone --depth 1 --branch "$JASP_TAG" --recurse-submodules --shallow-submodules \
|
|
https://github.com/jasp-stats/jasp-desktop.git "$SRC_DIR"
|
|
|
|
cd "$SRC_DIR"
|
|
JASP_COMMIT="$(git rev-parse HEAD)"
|
|
|
|
# ---------------------------------------------------------------------- build
|
|
log "configuring"
|
|
export CMAKE_C_COMPILER_LAUNCHER=ccache
|
|
export CMAKE_CXX_COMPILER_LAUNCHER=ccache
|
|
export CMAKE_Fortran_COMPILER_LAUNCHER=ccache
|
|
export CFLAGS="${CFLAGS:-} -fPIC"
|
|
export CXXFLAGS="${CXXFLAGS:-} -fPIC"
|
|
export FCFLAGS="${FCFLAGS:-} -fPIC"
|
|
export FFLAGS="${FFLAGS:-} -fPIC"
|
|
|
|
rm -rf "$BUILD_DIR"
|
|
cmake -S "$SRC_DIR" -B "$BUILD_DIR" -G Ninja \
|
|
-DCMAKE_BUILD_TYPE=Release \
|
|
-DCMAKE_INSTALL_PREFIX="$PREFIX" \
|
|
-DLINUX_LOCAL_BUILD=ON \
|
|
-Wno-dev
|
|
|
|
log "compiling JASP (-j$JOBS)"
|
|
ninja -C "$BUILD_DIR" -j"$JOBS"
|
|
|
|
# The R modules are the long pole: several hundred R packages compiled from
|
|
# source. buildAllDefaultJaspModules.R expects these directories to exist.
|
|
log "building R modules — this is the slow part"
|
|
mkdir -p "$BUILD_DIR"/Modules/{binary_pkgs,manifests,module_libs,Tools}
|
|
cd "$SRC_DIR/Tools"
|
|
Rscript buildAllDefaultJaspModules.R
|
|
|
|
# -------------------------------------------------------------------- staging
|
|
log "staging install tree"
|
|
rm -rf "$STAGE_DIR"
|
|
mkdir -p "$STAGE_DIR"
|
|
DESTDIR="$STAGE_DIR" ninja -C "$BUILD_DIR" install
|
|
|
|
install -d "$STAGE_DIR$PREFIX/Modules"
|
|
cp -a "$SRC_DIR/Tools/ModuleBundleBuildDir/Modules/." "$STAGE_DIR$PREFIX/Modules/"
|
|
|
|
if [[ -d "$BUILD_DIR/R/library" ]]; then
|
|
install -d "$STAGE_DIR$PREFIX/R/library"
|
|
cp -a "$BUILD_DIR/R/library/." "$STAGE_DIR$PREFIX/R/library/"
|
|
fi
|
|
|
|
# Desktop entry + icons, so the tarball is a complete install tree.
|
|
install -Dm644 /work/packaging/org.jaspstats.JASP.desktop \
|
|
"$STAGE_DIR/usr/share/applications/org.jaspstats.JASP.desktop"
|
|
|
|
if [[ -d "$STAGE_DIR$PREFIX/share/icons/hicolor" ]]; then
|
|
install -d "$STAGE_DIR/usr/share/icons/hicolor"
|
|
cp -a "$STAGE_DIR$PREFIX/share/icons/hicolor/." "$STAGE_DIR/usr/share/icons/hicolor/"
|
|
fi
|
|
|
|
install -d "$STAGE_DIR/usr/share/licenses/jasp-desktop-bin"
|
|
cd "$SRC_DIR"
|
|
find . -maxdepth 2 -name 'COPYING*' -o -maxdepth 2 -name 'LICENSE*' -type f \
|
|
| while read -r f; do install -m644 "$f" "$STAGE_DIR/usr/share/licenses/jasp-desktop-bin/"; done
|
|
|
|
# Strip build-host paths out of the staged tree so the tarball is relocatable.
|
|
find "$STAGE_DIR" -name '*.o' -delete 2>/dev/null || true
|
|
|
|
# ------------------------------------------------------------------- metadata
|
|
# Pin data: the PKGBUILD turns these into versioned `depends` entries, so an
|
|
# Arch R or Qt6 bump makes the package rebuild rather than silently break.
|
|
pkgver_of() { pacman -Q "$1" 2>/dev/null | awk '{print $2}'; }
|
|
|
|
R_FULL="$(pkgver_of r)"
|
|
R_MINOR="$(R --version | head -1 | grep -oE '[0-9]+\.[0-9]+' | head -1)"
|
|
QT_FULL="$(pkgver_of qt6-base)"
|
|
QT_MINOR="$(echo "$QT_FULL" | grep -oE '^[0-9]+\.[0-9]+')"
|
|
BOOST_FULL="$(pkgver_of boost-libs)"
|
|
|
|
JASP_VER="${JASP_TAG#v}"
|
|
TARBALL="jasp-desktop-${JASP_VER}-x86_64.tar.zst"
|
|
|
|
log "creating $TARBALL"
|
|
cd "$STAGE_DIR"
|
|
tar --zstd -cf "$OUT_DIR/$TARBALL" .
|
|
SHA256="$(sha256sum "$OUT_DIR/$TARBALL" | awk '{print $1}')"
|
|
SIZE="$(stat -c%s "$OUT_DIR/$TARBALL")"
|
|
|
|
cat >"$OUT_DIR/build-info.json" <<EOF
|
|
{
|
|
"jasp_version": "${JASP_VER}",
|
|
"jasp_tag": "${JASP_TAG}",
|
|
"jasp_commit": "${JASP_COMMIT}",
|
|
"tarball": "${TARBALL}",
|
|
"sha256": "${SHA256}",
|
|
"size_bytes": ${SIZE},
|
|
"r_version": "${R_FULL}",
|
|
"r_minor": "${R_MINOR}",
|
|
"qt6_version": "${QT_FULL}",
|
|
"qt6_minor": "${QT_MINOR}",
|
|
"boost_version": "${BOOST_FULL}"
|
|
}
|
|
EOF
|
|
|
|
log "done"
|
|
cat "$OUT_DIR/build-info.json"
|