build: survive low-memory boards in the receiver install script

The Raspberry Pi Zero 2 W (512 MB RAM) ran out of memory compiling
signaling.cpp — nlohmann/json peaks well above available RAM at -O3,
and ninja runs 6 parallel jobs on a quad-core — so the OOM killer
terminated the compiler with 'Killed signal terminated program
cc1plus'.

When less than 1.5 GB RAM is detected, the install script now adds
1 GB of temporary build-time swap (fallocate with a dd fallback,
removed on exit; some filesystems such as btrfs refuse swapfiles
outright, in which case it warns and continues) and compiles with a
single job. The cleanup trap also covers the SDL3 source directory.

The swap mechanics were live-tested with a small swapfile (swapon/
swapoff lifecycle); this dev machine's filesystem rejects swapfiles,
which is what exposed the need for the warning fallback. The Pi's
ext4 rootfs accepts them.
This commit is contained in:
2026-09-07 13:20:14 +02:00
parent 7c04506dde
commit 56e0d3662b
+47 -3
View File
@@ -34,6 +34,19 @@ ENABLE_SERVICE="${SC_RECEIVER_SERVICE:-1}"
log() { printf '\n=== %s\n' "$*"; }
die() { printf 'install-receiver: error: %s\n' "$*" >&2; exit 1; }
TEMP_SWAP=""
SDL_DIR=""
cleanup() {
if [ -n "${TEMP_SWAP}" ]; then
swapoff "${TEMP_SWAP}" 2>/dev/null || true
rm -f "${TEMP_SWAP}"
fi
if [ -n "${SDL_DIR}" ]; then
rm -rf "${SDL_DIR}"
fi
}
trap cleanup EXIT
[ "$(id -u)" = 0 ] || die "run with sudo (installs to ${INSTALL_DIR})"
[ -f "${REPO_ROOT}/meson.build" ] || die "run from the screen_cast repository"
command -v apt-get >/dev/null 2>&1 || die "this script supports apt-based systems only"
@@ -62,7 +75,6 @@ if ! apt-get install -y --no-install-recommends libsdl3-dev; then
log "libsdl3-dev is not packaged; building SDL3 from source (15-30 min on small boards)"
apt-get install -y --no-install-recommends cmake git
SDL_DIR="$(mktemp -d)"
trap 'rm -rf "${SDL_DIR}"' EXIT
git clone --depth 1 --branch release-3.2.x \
https://github.com/libsdl-org/SDL.git "${SDL_DIR}/SDL"
cmake -S "${SDL_DIR}/SDL" -B "${SDL_DIR}/build" \
@@ -82,13 +94,45 @@ if ! printf '#include <format>\nint main() { return 0; }\n' |
Trixie or newer ships one). Aborting before a long build."
fi
# --- memory-constrained boards ----------------------------------------------
# The signaling unit includes nlohmann/json.hpp, which can peak well above
# the RAM of small boards; the OOM killer then terminates the compiler
# ("Killed signal terminated program cc1plus"). Give such boards temporary
# swap and a single compile job.
BUILD_JOBS="$(nproc)"
MEM_TOTAL_KB="$(awk '/^MemTotal:/ {print $2}' /proc/meminfo)"
if [ "${MEM_TOTAL_KB}" -lt 1500000 ]; then
SWAP_TOTAL_KB="$(awk '/^SwapTotal:/ {print $2}' /proc/meminfo)"
if [ "${SWAP_TOTAL_KB}" -lt 1000000 ]; then
FREE_KB="$(df -k --output=avail / | awk 'NR==2 {print $1}')"
if [ "${FREE_KB}" -lt 1572864 ]; then
die "board has little RAM and not enough free disk for 1 GB of temporary build swap; build on a larger machine or add swap manually"
fi
log "low-memory board: adding 1 GB of temporary swap for the build (removed afterwards)"
TEMP_SWAP="/var/tmp/screencast-build.swap"
if ! (fallocate -l 1G "${TEMP_SWAP}" 2>/dev/null ||
dd if=/dev/zero of="${TEMP_SWAP}" bs=1M count=1024 status=none); then
die "failed to write the swapfile"
fi
chmod 600 "${TEMP_SWAP}"
if ! mkswap "${TEMP_SWAP}" >/dev/null 2>&1 || ! swapon "${TEMP_SWAP}" 2>/dev/null; then
# Some filesystems (e.g. btrfs) refuse swapfiles outright.
rm -f "${TEMP_SWAP}"
TEMP_SWAP=""
log "WARNING: could not activate a swapfile on this filesystem; continuing with a single compile job — the build may still run out of memory"
fi
fi
BUILD_JOBS=1
log "low-memory board: compiling with a single job"
fi
# --- build the receiver ------------------------------------------------------
log "configuring a receiver-only build in ${BUILD_DIR}"
rm -rf "${BUILD_DIR}"
meson setup "${BUILD_DIR}" "${REPO_ROOT}" -Dsender=false
log "compiling (this takes a few minutes on small boards)"
meson compile -C "${BUILD_DIR}"
log "compiling (this takes a while on small boards)"
meson compile -C "${BUILD_DIR}" --jobs "${BUILD_JOBS}"
if [ "${SKIP_TESTS}" != "1" ]; then
log "running the test suite"