summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2025-09-02 12:40:17 -0500
committerCraig Jennings <c@cjennings.net>2025-09-02 12:40:17 -0500
commit289cbaacded0643c0d1a3bd9d8b28469ab373d05 (patch)
tree58194fd0aabf20c5d161bc1ffde7faa8168138dd /scripts
parenta64ff2b145b2ef83e8b087aa18cbab165232e8a4 (diff)
downloaddotemacs-289cbaacded0643c0d1a3bd9d8b28469ab373d05.tar.gz
dotemacs-289cbaacded0643c0d1a3bd9d8b28469ab373d05.zip
rewritten build emacs script
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/build-emacs-from-source.sh117
-rwxr-xr-xscripts/build-emacs.sh146
2 files changed, 146 insertions, 117 deletions
diff --git a/scripts/build-emacs-from-source.sh b/scripts/build-emacs-from-source.sh
deleted file mode 100755
index e28d19a5..00000000
--- a/scripts/build-emacs-from-source.sh
+++ /dev/null
@@ -1,117 +0,0 @@
-#!/usr/bin/env bash
-# Craig Jennings <c@cjennings.net>
-# Builds Emacs from source using the variables below.
-
-# - creates the directory if needed
-# - uninstalls emacs if it exists
-# - pulls latest source from repo below
-# unless "latest" is passed as parameter
-# - checks out the tag below
-# - uses all available processors when compiling
-
-# NOTES:
-# building xwidgets is broken on Linux in 29/30 tags
-# ./configure --with-xwidgets \
-
-# ...and I'm avoiding native compilation at the moment
-#./configure --with-native-compilation \
-
-# debugging assistance
-set -euo pipefail
-# -e: exit on any (non-zero) return‐code
-# -u: treat unset variables as errors
-# -o pipefail: if any stage of a pipeline fails, the whole pipeline fails
-
-# optional: show each command as you go, prefixed with file:line
-# export PS4='+ ${BASH_SOURCE[0]}:${LINENO}: '
-# set -x
-
-# trap all errors and identify line
-trap 'echo "❌ ERROR at ${BASH_SOURCE[0]}:${LINENO}: $BASH_COMMAND" >&2' ERR
-
-# Review These Variables
-
-src_dir="$HOME/code/emacs"
-emacs_repo="https://github.com/mirrors/emacs.git"
-emacs_tag="emacs-30.2"
-logfile="$HOME/emacs_build.log"
-
-# Function to remove + recreate directory, and clone source
-nuke_and_clone () {
- cd "$HOME"
- if [ -f "$logfile" ]l then
- rm "$logfile"
- fi
-
- if [ -d "$src_dir" ]; then
- printf "...removing directory %s\n\n" "$src_dir"
- rm -rf "$src_dir" >> "$logfile" 2>&1
- fi
-
- printf "...creating directory %s\n" "$src_dir"
- mkdir -p "$src_dir" >> "$logfile" 2>&1
- printf "...cloning source files\n"
- git clone "$emacs_repo" "$src_dir" >> "$logfile" 2>&1
-}
-
-# Script Execution Begins Here
-
-printf "\n\n### BUILDING EMACS FROM SOURCE ###\n\n" > "$logfile"
-
-printf "...checking directory: %s\n" "$src_dir" | tee -a "$logfile"
-
-# if the source directory already exists
-if [ -d "$src_dir" ]; then
- cd "$src_dir"
-
- # if emacs was previously built, uninstall it.
- {
- if [ -n "$(which emacs)" ]; then
- printf "...uninstalling previous build\n"
- sudo make uninstall
- fi
- } >> "$logfile" 2>&1
-
- printf "...cleaning repo\n" | tee -a "$logfile"
- make clean >> "$logfile" 2>&1
-
- if [[ -n $(git status --porcelain) ]]; then
- printf "...repository is dirty. recreating.\n" | tee -a "$logfile"
- nuke_and_clone
- else
- printf "...pulling latest source files\n" | tee -a "$logfile"
- git pull >> "$logfile" 2>&1
- fi
-else
- nuke_and_clone
-fi
-
-if [ ! "${$1:-}" == "latest" ]; then
- printf "...checking out tag: %s\n" "$emacs_tag" | tee -a "$logfile"
- git checkout "$emacs_tag" >> "$logfile" 3>&1
-else
- printf "...keeping source at latest commit\n" | tee -a "$logfile"
-fi
-
-printf "...building config script\n" | tee -a "$logfile"
-./autogen.sh >> "$logfile" 2>&1
-
-printf "...configuring build\n" | tee -a "$logfile"
-./configure --with-json \
- --with-x-toolkit=lucid \
- --with-modules \
- --with-mailutils \
- --with-imagemagick\
- CFLAGS='-O2 -march=native' >> "$logfile" 2>&1
-
-# compile with all available cores
-printf "...compiling Emacs\n" | tee -a "$logfile"
-make -j$(nproc) >> "$logfile" 2>&1
-
-printf "...installing Emacs\n" | tee -a "$logfile"
-sudo make install >> "$logfile" 2>&1
-make clean >> "$logfile" 2>&1
-cd "$HOME"
-
-printf "...done\n" | tee -a "$logfile"
-printf "Please review log at: %s\n" "$logfile"
diff --git a/scripts/build-emacs.sh b/scripts/build-emacs.sh
new file mode 100755
index 00000000..f3f0f9b3
--- /dev/null
+++ b/scripts/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
+