aboutsummaryrefslogtreecommitdiff
path: root/provision-static.sh
diff options
context:
space:
mode:
Diffstat (limited to 'provision-static.sh')
-rwxr-xr-xprovision-static.sh190
1 files changed, 190 insertions, 0 deletions
diff --git a/provision-static.sh b/provision-static.sh
new file mode 100755
index 0000000..c2125ee
--- /dev/null
+++ b/provision-static.sh
@@ -0,0 +1,190 @@
+#!/bin/sh
+# provision-static.sh - build the static libraries mouseboard needs.
+#
+# Usage: ./provision-static.sh
+#
+# Debian (and friends) ship no static libwayland-client or libxkbcommon, so
+# this fetches and builds them (plus libffi) with a musl toolchain into
+# musl-sysroot/, ready for `make static`. Run it once per machine; an unchanged
+# completed sysroot is reused, while changed inputs trigger a clean rebuild.
+#
+# Prerequisites (Debian):
+# apt install musl-tools meson ninja-build bison pkgconf curl libexpat1-dev
+set -eu
+
+ROOT="$(cd "$(dirname "$0")" && pwd)"
+SYSROOT="$ROOT/musl-sysroot"
+WORK="$ROOT/musl-build"
+HOSTCC="${HOSTCC:-cc}"
+
+# Pick the musl target compiler. An explicit CC always wins. Otherwise, if the
+# default cc already targets musl (Alpine, Void-musl) use it directly; on a
+# glibc host (Debian, Arch) fall back to the musl-gcc wrapper from musl-tools.
+if [ -n "${CC:-}" ]; then
+ BASECC="$CC"
+elif command -v cc >/dev/null 2>&1 && cc -dumpmachine 2>/dev/null | grep -q musl; then
+ BASECC="cc"
+else
+ BASECC="musl-gcc"
+fi
+
+# Pinned versions and checksums. Override a version only together with its sha.
+FFI_VER="${FFI_VER:-3.4.6}"
+FFI_SHA="${FFI_SHA:-b0dea9df23c863a7a50e825440f3ebffabd65df1497108e5d437747843895a4e}"
+WL_VER="${WL_VER:-1.23.1}"
+WL_SHA="${WL_SHA:-864fb2a8399e2d0ec39d56e9d9b753c093775beadc6022ce81f441929a81e5ed}"
+XKB_VER="${XKB_VER:-1.7.0}"
+XKB_SHA="${XKB_SHA:-65782f0a10a4b455af9c6baab7040e2f537520caa2ec2092805cdfd36863b247}"
+
+command -v "$BASECC" >/dev/null 2>&1 || {
+ echo "missing musl compiler: $BASECC" >&2
+ echo " glibc host (Debian, Arch): install musl-tools for musl-gcc" >&2
+ echo " or point CC at your musl compiler: CC=... $0" >&2
+ exit 1
+}
+for t in "$HOSTCC" meson ninja bison curl pkg-config sha256sum \
+ tar make nproc sed; do
+ command -v "$t" >/dev/null 2>&1 || { echo "missing tool: $t" >&2; exit 1; }
+done
+JOBS="$(nproc)"
+
+# wayland-scanner is built from source below and parses XML with expat.
+pkg-config --exists expat || {
+ echo "missing dev library: expat (Debian: libexpat1-dev)" >&2; exit 1; }
+
+BASECC_PATH="$(command -v "$BASECC")"
+HOSTCC_PATH="$(command -v "$HOSTCC")"
+BASECC_VERSION="$("$BASECC" --version | sed -n '1p')"
+HOSTCC_VERSION="$("$HOSTCC" --version | sed -n '1p')"
+MULTIARCH="$("$BASECC" -print-multiarch 2>/dev/null || echo x86_64-linux-gnu)"
+SCRIPT_SHA="$(sha256sum "$0" | sed 's/ .*//')"
+STAMP="$SYSROOT/.provisioned"
+INPUTS="recipe=$SCRIPT_SHA
+ffi=$FFI_VER $FFI_SHA
+wayland=$WL_VER $WL_SHA
+xkbcommon=$XKB_VER $XKB_SHA
+target-cc=$BASECC_PATH
+target-cc-version=$BASECC_VERSION
+host-cc=$HOSTCC_PATH
+host-cc-version=$HOSTCC_VERSION
+multiarch=$MULTIARCH
+cflags=${CFLAGS:-}
+cppflags=${CPPFLAGS:-}
+ldflags=${LDFLAGS:-}"
+
+sysroot_complete() {
+ [ -x "$SYSROOT/bin/cc" ] &&
+ [ -x "$SYSROOT/bin/wayland-scanner" ] &&
+ [ -f "$SYSROOT/lib/libffi.a" ] &&
+ [ -f "$SYSROOT/lib/libwayland-client.a" ] &&
+ [ -f "$SYSROOT/lib/libxkbcommon.a" ] &&
+ [ -f "$SYSROOT/lib/pkgconfig/libffi.pc" ] &&
+ [ -f "$SYSROOT/lib/pkgconfig/wayland-client.pc" ] &&
+ [ -f "$SYSROOT/lib/pkgconfig/xkbcommon.pc" ] &&
+ [ -f "$SYSROOT/include/wayland-client.h" ] &&
+ [ -f "$SYSROOT/include/xkbcommon/xkbcommon.h" ]
+}
+
+if [ -d "$SYSROOT" ]; then
+ OLD_INPUTS=""
+ [ ! -f "$STAMP" ] || OLD_INPUTS="$(cat "$STAMP")"
+ if [ "$OLD_INPUTS" != "$INPUTS" ] || ! sysroot_complete; then
+ echo "static sysroot stale or incomplete; rebuilding $SYSROOT"
+ rm -rf "$SYSROOT"
+ fi
+fi
+
+# Fetch a file if absent, then verify its checksum (fails loud on mismatch).
+fetch() { # url sha
+ file="$(basename "$1")"
+ [ -f "$file" ] || curl -fsSLO "$1"
+ echo "$2 $file" | sha256sum -c - || { rm -f "$file"; exit 1; }
+}
+
+# Sysroot libs resolve first while building the deps themselves (wayland
+# needs the sysroot's libffi.pc).
+export PKG_CONFIG_PATH="$SYSROOT/lib/pkgconfig:$SYSROOT/share/pkgconfig:${PKG_CONFIG_PATH:-}"
+
+mkdir -p "$WORK" "$SYSROOT/bin"
+
+# musl-gcc only exposes musl's libc headers, not the Linux kernel uapi headers
+# (linux/*, asm/*) from linux-libc-dev. Wrap it to add them at lowest priority
+# so musl's libc headers still win. The wrapper lands in musl-sysroot/bin/cc;
+# `make static` compiles with it too. On musl-native distros the extra
+# -idirafter flags are harmless.
+MCC="$SYSROOT/bin/cc"
+printf '#!/bin/sh\nexec "%s" -idirafter /usr/include -idirafter /usr/include/%s "$@"\n' \
+ "$BASECC_PATH" "$MULTIARCH" > "$MCC"
+chmod +x "$MCC"
+
+cd "$WORK"
+
+# ---- libffi (autotools): wayland's marshalling needs it ----
+if [ ! -f "$SYSROOT/lib/pkgconfig/libffi.pc" ]; then
+ fetch "https://github.com/libffi/libffi/releases/download/v$FFI_VER/libffi-$FFI_VER.tar.gz" "$FFI_SHA"
+ rm -rf "libffi-$FFI_VER"
+ tar xf "libffi-$FFI_VER.tar.gz"
+ cd "libffi-$FFI_VER"
+ ./configure CC="$MCC" --prefix="$SYSROOT" --libdir="$SYSROOT/lib" \
+ --disable-shared --enable-static --disable-docs
+ make -j"$JOBS"
+ make install
+ cd "$WORK"
+fi
+
+# ---- wayland-scanner (native host tool, pinned to WL_VER) ----
+# wayland's library build needs a wayland-scanner at least as new as the
+# library, but distros ship older ones (CI had 1.22.0 vs 1.23.1). Build it
+# from the pinned source with the host compiler (glibc + host expat) into the
+# sysroot, so the version always matches and nothing depends on the host copy.
+# The static mouseboard build uses this scanner too (see Makefile).
+if [ ! -x "$SYSROOT/bin/wayland-scanner" ]; then
+ fetch "https://gitlab.freedesktop.org/wayland/wayland/-/releases/$WL_VER/downloads/wayland-$WL_VER.tar.xz" "$WL_SHA"
+ rm -rf "wayland-$WL_VER" wl-scanner-build
+ tar xf "wayland-$WL_VER.tar.xz"
+ CC="$HOSTCC_PATH" meson setup "wayland-$WL_VER" wl-scanner-build \
+ --prefix="$SYSROOT" --libdir=lib --buildtype=release \
+ -Dscanner=true -Dlibraries=false -Dtests=false \
+ -Ddocumentation=false -Ddtd_validation=false
+ ninja -C wl-scanner-build
+ ninja -C wl-scanner-build install
+fi
+
+# ---- wayland (libraries, static/musl; uses the scanner built above) ----
+if [ ! -f "$SYSROOT/lib/pkgconfig/wayland-client.pc" ]; then
+ fetch "https://gitlab.freedesktop.org/wayland/wayland/-/releases/$WL_VER/downloads/wayland-$WL_VER.tar.xz" "$WL_SHA"
+ rm -rf "wayland-$WL_VER" wl-build
+ tar xf "wayland-$WL_VER.tar.xz"
+ CC="$MCC" meson setup "wayland-$WL_VER" wl-build \
+ --prefix="$SYSROOT" --libdir=lib -Ddefault_library=static \
+ --buildtype=release \
+ -Dscanner=false -Dlibraries=true -Dtests=false \
+ -Ddocumentation=false -Ddtd_validation=false
+ ninja -C wl-build
+ ninja -C wl-build install
+fi
+
+# ---- libxkbcommon (no x11, registry, tools, docs -> no extra deps) ----
+if [ ! -f "$SYSROOT/lib/pkgconfig/xkbcommon.pc" ]; then
+ fetch "https://xkbcommon.org/download/libxkbcommon-$XKB_VER.tar.xz" "$XKB_SHA"
+ rm -rf "libxkbcommon-$XKB_VER" xkb-build
+ tar xf "libxkbcommon-$XKB_VER.tar.xz"
+ CC="$MCC" meson setup "libxkbcommon-$XKB_VER" xkb-build \
+ --prefix="$SYSROOT" --libdir=lib -Ddefault_library=static \
+ --buildtype=release \
+ -Denable-x11=false -Denable-docs=false -Denable-xkbregistry=false \
+ -Denable-tools=false -Denable-bash-completion=false
+ ninja -C xkb-build
+ ninja -C xkb-build install
+fi
+
+if ! sysroot_complete; then
+ echo "static sysroot incomplete after provisioning" >&2
+ exit 1
+fi
+printf '%s\n' "$INPUTS" >"$STAMP.tmp"
+mv "$STAMP.tmp" "$STAMP"
+
+echo
+echo "sysroot ready: $SYSROOT"
+echo "build the static binary with: make static"