diff options
| author | Craig Jennings <c@cjennings.net> | 2025-09-02 12:40:17 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2025-09-02 12:40:17 -0500 |
| commit | 289cbaacded0643c0d1a3bd9d8b28469ab373d05 (patch) | |
| tree | 58194fd0aabf20c5d161bc1ffde7faa8168138dd /scripts | |
| parent | a64ff2b145b2ef83e8b087aa18cbab165232e8a4 (diff) | |
| download | dotemacs-289cbaacded0643c0d1a3bd9d8b28469ab373d05.tar.gz dotemacs-289cbaacded0643c0d1a3bd9d8b28469ab373d05.zip | |
rewritten build emacs script
Diffstat (limited to 'scripts')
| -rwxr-xr-x | scripts/build-emacs-from-source.sh | 117 | ||||
| -rwxr-xr-x | scripts/build-emacs.sh | 146 |
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 + |
