summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2025-09-03 02:15:48 -0500
committerCraig Jennings <c@cjennings.net>2025-09-03 02:15:48 -0500
commitc167aea5bcc1572eccdc6dcf6cf82c48547c1d78 (patch)
treee3065118e2e56fe75814c143806898e3bd95efa6
parent1464aaa2d08f138cf8a058bf09114b4484775182 (diff)
adding build-emacs script
-rwxr-xr-xdotfiles/system/.local/bin/build-emacs.sh146
1 files changed, 146 insertions, 0 deletions
diff --git a/dotfiles/system/.local/bin/build-emacs.sh b/dotfiles/system/.local/bin/build-emacs.sh
new file mode 100755
index 0000000..f3f0f9b
--- /dev/null
+++ b/dotfiles/system/.local/bin/build-emacs.sh
@@ -0,0 +1,146 @@
+#!/usr/bin/env bash
+# Craig Jennings <c@cjennings.net>
+# Build & install Emacs from source
+# safe, versioned, user-local, blunt, fast, reversible.
+
+set -euo pipefail
+
+### --------- CONFIG (edit these) ---------
+# Where the git checkout lives:
+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}"
+
+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; }
+
+trap 'echo "ERROR: see $LOGFILE" >&2' ERR
+
+say ">>> Building Emacs"
+say "SRC_DIR=$SRC_DIR"
+say "CHECKOUT_REF=$CHECKOUT_REF"
+say "PREFIX=$PREFIX"
+say "LOGFILE=$LOGFILE"
+
+# Fetch or update source
+if [[ -d "$SRC_DIR/.git" ]]; then
+ say "...updating existing checkout"
+ (cd "$SRC_DIR" && run "git fetch --tags --prune" && run "git status --porcelain")
+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}"
+ }
+fi
+
+# Checkout desired ref/tag
+(
+ cd "$SRC_DIR"
+ run "git fetch --tags --force"
+ run "git checkout ${CHECKOUT_REF}"
+)
+
+# Autogen/bootstrap (needed for git checkouts)
+if [[ -x "$SRC_DIR/autogen.sh" ]]; then
+ say "...running autogen.sh"
+ (cd "$SRC_DIR" && run "./autogen.sh")
+fi
+
+# Configure flags
+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")
+fi
+
+# xwidgets if requested
+if [[ $ENABLE_XWIDGETS -eq 1 ]]; then
+ conf_flags+=("--with-xwidgets")
+fi
+
+# Prefer system tree-sitter if present
+if pkg-config --exists tree-sitter 2>/dev/null; then
+ conf_flags+=("--with-tree-sitter")
+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}"
+)
+
+# Install to user-local prefix
+say "...installing to ${PREFIX}"
+(
+ cd "$SRC_DIR"
+ run "make install"
+)
+
+# ymlink all installed executables (emacs, emacsclient, etags, etc.)
+mkdir -p "$HOME/.local/bin"
+
+# Atomic swap: build symlinks in a temp dir, then move them into place.
+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"
+done
+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
+