summaryrefslogtreecommitdiff
path: root/dotfiles/system/.local/bin/build-emacs.sh
diff options
context:
space:
mode:
Diffstat (limited to 'dotfiles/system/.local/bin/build-emacs.sh')
-rwxr-xr-xdotfiles/system/.local/bin/build-emacs.sh179
1 files changed, 74 insertions, 105 deletions
diff --git a/dotfiles/system/.local/bin/build-emacs.sh b/dotfiles/system/.local/bin/build-emacs.sh
index f3f0f9b..a73e996 100755
--- a/dotfiles/system/.local/bin/build-emacs.sh
+++ b/dotfiles/system/.local/bin/build-emacs.sh
@@ -1,146 +1,115 @@
#!/usr/bin/env bash
# Craig Jennings <c@cjennings.net>
# Build & install Emacs from source
-# safe, versioned, user-local, blunt, fast, reversible.
+# safe, user-local, fast, versioned.
-set -euo pipefail
+set -Eeuo pipefail
+IFS=$'\n\t'
-### --------- CONFIG (edit these) ---------
-# Where the git checkout lives:
+# ---------- Config (override via env) ----------
SRC_DIR="${SRC_DIR:-$HOME/code/emacs-src}"
-
-# Which repo/branch/tag to build:
EMACS_REPO="${EMACS_REPO:-https://git.savannah.gnu.org/git/emacs.git}"
-CHECKOUT_REF="${CHECKOUT_REF:-emacs-29.2}" # e.g. "emacs-30.1", "master", "emacs-29"
-
-# Install prefix (keeps versions side-by-side):
-PREFIX_BASE="${PREFIX_BASE:-$HOME/.local/opt}"
-PREFIX="${PREFIX:-$PREFIX_BASE/${CHECKOUT_REF}}"
-
-# Optional knobs:
-ENABLE_NATIVE="${ENABLE_NATIVE:-0}" # 1 to enable native-comp if toolchain supports it
-ENABLE_PGTK="${ENABLE_PGTK:-0}" # 1 to use pgtk (Wayland-only build)
-ENABLE_XWIDGETS="${ENABLE_XWIDGETS:-0}" # 1 to enable xwidgets (known flaky on some 29/30 tags)
-MAKE_JOBS="${MAKE_JOBS:-$(command -v nproc >/dev/null 2>&1 && nproc || sysctl -n hw.ncpu || echo 4)}"
-
-# CFLAGS (tune lightly; keep reproducible):
-CFLAGS_OVERRIDES="${CFLAGS_OVERRIDES:--O2 -march=native}"
-
+CHECKOUT_REF="${CHECKOUT_REF:-emacs-30.2}"
+PREFIX_BASE="${PREFIX_BASE:-$HOME/.local/src}"
+PREFIX="${PREFIX:-$PREFIX_BASE/emacs-${CHECKOUT_REF}}"
LOG_DIR="${LOG_DIR:-$HOME/.cache/build-logs}"
-mkdir -p "$LOG_DIR"
-LOGFILE="$LOG_DIR/emacs-build-$(date +%Y%m%d-%H%M%S)-${CHECKOUT_REF}.log"
-### ---------------------------------------
-
-say() { printf '%s\n' "$*" | tee -a "$LOGFILE" ; }
-run() { say "+ $*"; eval "$@" >>"$LOGFILE" 2>&1; }
+ENABLE_NATIVE="${ENABLE_NATIVE:-1}"
+WITH_PGTK="${WITH_PGTK:-auto}"
+JOBS="${JOBS:-auto}"
+EXTRA_CONFIG="${EXTRA_CONFIG:-}"
-trap 'echo "ERROR: see $LOGFILE" >&2' ERR
+# ---------- Preflight ----------
+umask 022
+mkdir -p "$LOG_DIR" "$PREFIX_BASE" "$HOME/.local/bin"
+: "${LOGFILE:=$LOG_DIR/emacs-build-$(date +%Y%m%d-%H%M%S)-${CHECKOUT_REF}.log}"
-say ">>> Building Emacs"
-say "SRC_DIR=$SRC_DIR"
-say "CHECKOUT_REF=$CHECKOUT_REF"
-say "PREFIX=$PREFIX"
-say "LOGFILE=$LOGFILE"
+say() { printf '>>> %s\n' "$*" | tee -a "$LOGFILE" ; }
+run() { say "+ $*"; eval "$@" >>"$LOGFILE" 2>&1; }
+on_err(){ ec=$?; echo "ERROR [$ec] - see $LOGFILE" >&2; tail -n 80 "$LOGFILE" >&2 || true; exit "$ec"; }
+trap on_err ERR
-# Fetch or update source
+# ---------- Clone/update ----------
if [[ -d "$SRC_DIR/.git" ]]; then
- say "...updating existing checkout"
- (cd "$SRC_DIR" && run "git fetch --tags --prune" && run "git status --porcelain")
+ run "git -C '$SRC_DIR' fetch --tags --prune"
else
- say "...cloning source"
mkdir -p "$(dirname "$SRC_DIR")"
- run "git clone --depth=1 --branch ${CHECKOUT_REF} ${EMACS_REPO} ${SRC_DIR}" || {
- # If ref isn’t a branch, do full clone then checkout tag
- run "git clone ${EMACS_REPO} ${SRC_DIR}"
- }
+ run "git clone --origin origin '$EMACS_REPO' '$SRC_DIR'"
fi
-# Checkout desired ref/tag
-(
- cd "$SRC_DIR"
- run "git fetch --tags --force"
- run "git checkout ${CHECKOUT_REF}"
-)
+run "git -C '$SRC_DIR' reset --hard HEAD"
+run "git -C '$SRC_DIR' clean -fdx"
+run "git -C '$SRC_DIR' checkout -f '$CHECKOUT_REF'"
+run "git -C '$SRC_DIR' submodule update --init --recursive || true"
-# Autogen/bootstrap (needed for git checkouts)
+# ---------- Autogen ----------
if [[ -x "$SRC_DIR/autogen.sh" ]]; then
- say "...running autogen.sh"
- (cd "$SRC_DIR" && run "./autogen.sh")
+ run "cd '$SRC_DIR' && ./autogen.sh"
fi
-# Configure flags
+# ---------- Configure flags (ARRAY!) ----------
conf_flags=(
"--prefix=${PREFIX}"
"--with-json"
"--with-modules"
- "--with-cairo"
- "--with-harfbuzz"
- "--with-native-compilation=$( [[ $ENABLE_NATIVE -eq 1 ]] && echo yes || echo no )"
- "--with-mailutils"
- "--with-imagemagick"
)
-# pgtk vs X
-if [[ $ENABLE_PGTK -eq 1 ]]; then
- conf_flags+=("--with-pgtk" "--without-x")
-else
- conf_flags+=("--with-x" "--with-x-toolkit=gtk3")
+# Wayland/X choice
+if [[ "$WITH_PGTK" == "auto" ]]; then
+ if [[ -n "${WAYLAND_DISPLAY:-}" ]]; then WITH_PGTK="yes"; else WITH_PGTK="no"; fi
fi
-
-# xwidgets if requested
-if [[ $ENABLE_XWIDGETS -eq 1 ]]; then
- conf_flags+=("--with-xwidgets")
+if [[ "$WITH_PGTK" == "yes" ]]; then
+ conf_flags+=("--with-pgtk")
+else
+ conf_flags+=("--with-x-toolkit=lucid")
fi
-# Prefer system tree-sitter if present
-if pkg-config --exists tree-sitter 2>/dev/null; then
- conf_flags+=("--with-tree-sitter")
+# Native-compilation
+if [[ "$ENABLE_NATIVE" == "1" ]]; then
+ conf_flags+=("--with-native-compilation=yes")
+else
+ conf_flags+=("--with-native-compilation=no")
fi
-say "...configure flags:"
-printf ' %s\n' "${conf_flags[@]}" | tee -a "$LOGFILE"
-
-# Configure
-mkdir -p "$PREFIX" # ensure we can write there
-(
- cd "$SRC_DIR"
- run "env CFLAGS='${CFLAGS_OVERRIDES}' ./configure ${conf_flags[*]}"
-)
-
-# Build (and bootstrap if needed)
-say "...compiling (jobs=$MAKE_JOBS)"
-(
- cd "$SRC_DIR"
- # master sometimes needs bootstrap after significant changes; harmless otherwise:
- run "make -j${MAKE_JOBS}"
+# Useful extras (disable later via EXTRA_CONFIG if missing deps)
+conf_flags+=(
+ "--with-cairo"
+ "--with-harfbuzz"
+ "--with-tree-sitter"
+ "--with-imagemagick"
+ "--with-mailutils"
)
-# Install to user-local prefix
-say "...installing to ${PREFIX}"
-(
- cd "$SRC_DIR"
- run "make install"
-)
+# Optional extra flags from env
+if [[ -n "$EXTRA_CONFIG" ]]; then
+ # shellcheck disable=SC2206
+ conf_flags+=($EXTRA_CONFIG)
+fi
-# ymlink all installed executables (emacs, emacsclient, etags, etc.)
-mkdir -p "$HOME/.local/bin"
+# ---------- Build & install ----------
+mkdir -p "$PREFIX"
+# Temporarily change IFS to space for configure argument expansion
+old_ifs="$IFS"
+IFS=' '
+run "cd '$SRC_DIR' && ./configure ${conf_flags[*]}"
+IFS="$old_ifs"
+# If you prefer strict array expansion (safer with spaces in flags), use: ./configure "${conf_flags[@]}"
+
+if [[ "$JOBS" == "auto" ]]; then
+ if command -v nproc >/dev/null 2>&1; then JOBS=$(nproc); else JOBS=4; fi
+fi
+run "cd '$SRC_DIR' && make -j$JOBS"
+run "cd '$SRC_DIR' && make install"
-# Atomic swap: build symlinks in a temp dir, then move them into place.
+# ---------- Symlinks ----------
+run "ln -sfn '$PREFIX' '$PREFIX_BASE/emacs-current'"
tmpdir="$(mktemp -d)"
-for exe in "$PREFIX/bin/"*; do
- [ -x "$exe" ] || continue
- name="$(basename "$exe")"
- ln -s "$exe" "$tmpdir/$name"
-done
-
-# Move into ~/.local/bin (overwriting existing symlinks/files with same names)
-for link in "$tmpdir"/*; do
- name="$(basename "$link")"
- mv -f "$link" "$HOME/.local/bin/$name"
+for exe in "$PREFIX/bin/emacs" "$PREFIX/bin/emacsclient"; do
+ [[ -x "$exe" ]] || continue
+ ln -s "$exe" "$tmpdir/$(basename "$exe")"
done
+mv -f "$tmpdir"/* "$HOME/.local/bin/" || { echo "Failed to install shims to ~/.local/bin" >&2; exit 72; }
rmdir "$tmpdir"
-# Optional: quick sanity print
command -v emacs >/dev/null && emacs --version | head -n1 || true
command -v emacsclient >/dev/null && emacsclient --version | head -n1 || true
-
+echo "Done. See $LOGFILE"