From a50e2d7b5e663e3e49df6ef559e0892a04f0ffae Mon Sep 17 00:00:00 2001
From: Philip Peterson <1326208+philip-peterson@users.noreply.github.com>
Date: Sat, 10 Oct 2026 10:27:11 -0800
Subject: [PATCH] Cap ninja parallelism to stop flutter run from OOMing
flutter_tools shells out to bare `ninja -C
install` with no -j
flag, so ninja defaults to nproc+2 parallel compile/link jobs. On this
6-core/7.6GiB box that's enough concurrent clang jobs (sqlite3's
single-TU amalgamation is the worst offender) to trip systemd-oomd
well before swap fills up.
Add tools/ninja-jcap, a PATH-shadowing ninja shim that caps jobs via
NINJA_JOBS (default 2), and have the Taskfile prepend it inline in the
run command. Task's `env:` block can't override PATH itself (the OS
env wins), so the shim has to go on PATH via the shell command line.
Co-Authored-By: Claude Sonnet 5
---
Taskfile.yml | 20 ++++++++++++++++++++
tools/ninja-jcap/ninja | 31 +++++++++++++++++++++++++++++++
2 files changed, 51 insertions(+)
create mode 100644 Taskfile.yml
create mode 100755 tools/ninja-jcap/ninja
diff --git a/Taskfile.yml b/Taskfile.yml
new file mode 100644
index 0000000..c9c3b31
--- /dev/null
+++ b/Taskfile.yml
@@ -0,0 +1,20 @@
+version: '3'
+
+vars:
+ FLUTTER: /var/home/ironmagma/Code/.flutter-sdk/bin/flutter
+
+tasks:
+ default:
+ desc: Launch Layer Wizard
+ env:
+ # GTK/glib/etc. come from Homebrew (brew install gtk+3), not rpm-ostree,
+ # since they're only needed to build this one app, not the OS image.
+ PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/lib/pkgconfig:/home/linuxbrew/.linuxbrew/share/pkgconfig:/home/linuxbrew/.linuxbrew/opt/xorgproto/share/pkgconfig
+ cmds:
+ # flutter_tools shells out to bare `ninja -C install` with no -j
+ # flag, so ninja defaults to nproc+2 parallel compile/link jobs. That's
+ # enough to trip systemd-oomd on this machine (6 cores, 7.6GiB RAM).
+ # (Task's `env:` block can't override PATH itself -- the OS env wins --
+ # so the shim has to be prepended inline here instead.) See
+ # tools/ninja-jcap for the shim that caps it.
+ - 'PATH="{{.ROOT_DIR}}/tools/ninja-jcap:$PATH" {{.FLUTTER}} run -d linux'
diff --git a/tools/ninja-jcap/ninja b/tools/ninja-jcap/ninja
new file mode 100755
index 0000000..cbb0b7f
--- /dev/null
+++ b/tools/ninja-jcap/ninja
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+# Shim that caps ninja's parallelism before handing off to the real binary.
+#
+# `flutter run`/`flutter build` for the linux target invoke bare `ninja -C
+# install` with no -j flag (flutter_tools gives no way to pass one), so
+# ninja defaults to nproc+2 concurrent compile/link jobs. On this machine
+# (6 cores, 7.6GiB RAM) that's enough parallel clang jobs -- especially
+# linking the sqlite3 amalgamation with debug info -- to trip systemd-oomd
+# well before swap fills up. Capping jobs here keeps `task` usable without
+# patching flutter_tools.
+#
+# Override with NINJA_JOBS=N if this box has more headroom.
+set -euo pipefail
+
+self_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
+
+real_ninja=""
+IFS=':' read -ra path_dirs <<< "$PATH"
+for dir in "${path_dirs[@]}"; do
+ if [[ "$dir" != "$self_dir" && -x "$dir/ninja" ]]; then
+ real_ninja="$dir/ninja"
+ break
+ fi
+done
+
+if [[ -z "$real_ninja" ]]; then
+ echo "ninja-jcap: couldn't find a real ninja later in PATH" >&2
+ exit 1
+fi
+
+exec "$real_ninja" -j "${NINJA_JOBS:-2}" "$@"