Skip to content

Instantly share code, notes, and snippets.

@abougouffa
Last active December 8, 2024 00:30
Show Gist options
  • Save abougouffa/4bcccc6d7dc34cf52e2877ca34445bc3 to your computer and use it in GitHub Desktop.
Save abougouffa/4bcccc6d7dc34cf52e2877ca34445bc3 to your computer and use it in GitHub Desktop.
A helper script to build Emacs from source on Debian/Ubuntu
#!/bin/bash
# -*- sh-basic-offset: 2; tab-width: 2; -*-
# set -x
# Initially based on the emacs-git AUR package
## Build options
USE_CLANG= # Use Clang instead of GCC.
LINK_TIME_OPTIMIZATION="YES" # Enable link-time optimization.
AOT_ELISP= # Compile all elisp files provided by upstream.
MAKE_TRAMPOLINES= # Compile jitted Elisp files with trampolines.
ALSA= # Linux sound support.
MAKE_DOCS_HTML= # Generate and install html documentation.
MAKE_DOCS_PDF= # Generate and install pdf documentation. You need a TeX installation.
EMACS_BRANCH="emacs-30" # Emacs' branch to be built.
UI="GTK3" # GTK3, PGTK, LUCID
XWIDGETS= # XWidgets support
PERFORMANCE_TWEAKS="YES" # Apply some performance related tweaks
# ===================================================================
emacs_system_make_depends=(
'git'
'gcc'
'autoconf'
)
# Maybe not complete list
debian_system_depends=(
'libgnutls28-dev' 'libxml2-dev' 'libharfbuzz-dev' 'texinfo' 'libxi-dev'
'libjpeg-dev' 'libpng-dev' 'giflib-tools' 'libgif-dev' 'libwebp-dev' 'libtiff-dev' 'libxpm-dev'
'libjansson-dev' # Native JSON support for Emacs 29, not needed for 30+
'libgccjit-12-dev' # Native compile (28+)
'tree-sitter-dev' # Treesitter (29+)
'libsqlite3-dev' # SQLite
'libgpm-dev' # GPM
'libcairo2-dev' # Cairo
)
src_dir=$PWD/emacs
# ===================================================================
if [[ "${USE_CLANG}" == "YES" ]]; then
export CC="/usr/bin/clang"
export CXX="/usr/bin/clang++"
export CPP="/usr/bin/clang -E"
export LD="/usr/bin/lld"
export AR="/usr/bin/llvm-ar"
export AS="/usr/bin/llvm-as"
export CCFLAGS+=' -fuse-ld=lld'
export CXXFLAGS+=' -fuse-ld=lld'
system_make_depends+=('clang' 'lld' 'llvm')
fi
if [[ "${UI}" == "LUCID" ]]; then
system_depends+=('dbus' 'hicolor-icon-theme' 'libxinerama-dev' 'libxfixes-dev' 'librsvg2-dev' 'xaw3dg-dev' 'libxrandr-dev' 'libxi-dev' 'libsm-dev' 'xcb' 'libxcb1-dev')
system_make_depends+=('x11proto-dev')
elif [[ "${UI}" == "GTK3" ]]; then
system_depends+=('libgtk-3-dev' 'libsm-dev' 'xcb' 'libxcb1-dev')
system_make_depends+=('x11proto-dev' 'libxi-dev')
elif [[ "${UI}" == "PGTK" ]]; then
system_depends+=('libgtk-3-dev' 'libsm-dev' 'xcb' 'libxcb1-dev')
system_make_depends+=('x11proto-dev' 'libxi-dev')
fi
if [[ "${XWIDGETS}" == "YES" ]]; then
system_make_depends+=('libwebkit2gtk-4.0-dev')
fi
if [[ "${ALSA}" == "YES" ]]; then
system_depends+=('alsa-lib')
fi
if [[ "${MAKE_DOCS_PDF}" == "YES" ]] && [[ ! -d '/usr/local/texlive' ]]; then
system_make_depends+=('texlive-core')
fi
emacs-install-dependencies() {
apt install "${debian_system_depends[@]}" "${emacs_system_make_depends[@]}"
}
proxy-enable() {
if ping -c3 -W2 1.1.1.1 | grep -q "0 received"; then
echo "Cannot ping WAN, setting proxies"
export https_proxy=http://SOME_LOCAL_PROXY:8080/
export http_proxy=http://SOME_LOCAL_PROXY:8080/
export ftp_proxy=http://SOME_LOCAL_PROXY:8080/
export no_proxy=localhost,127.0.0.1,.local,.SOME_LOCAL_TLD
fi
}
# There is no need to run autogen.sh after first checkout.
# Doing so, breaks incremental compilation.
emacs-prepare() {
# proxy-enable
if [[ ! -d "${src_dir}" ]]; then
git clone https://github.com/emacs-mirror/emacs.git "${src_dir}" -b "${EMACS_BRANCH}"
else
cd "${src_dir}" || exit 1
git stash --include-untracked
git pull origin
git checkout "${EMACS_BRANCH}"
fi
[[ -d "${src_dir}/build" ]] && rm -rf "${src_dir}/build"
[[ -x configure ]] || (./autogen.sh git && ./autogen.sh autoconf)
mkdir -p "${src_dir}/build"
}
emacs-check() {
cd "${src_dir}/build" || exit 1
make check
}
emacs-build() {
cd "${src_dir}/build" || exit 1
if [[ "${PERFORMANCE_TWEAKS}" == "YES" ]]; then
# This disables the GC mark trace buffer for about 5% better garbage collection performance
config_options+=('--disable-gc-mark-trace')
# Better compilation optimization
export CFLAGS+="-O2 -pipe -march=native -mtune=native -fomit-frame-pointer"
fi
local config_options=(
--prefix="$HOME/.local"
--sysconfdir=/etc
--libexecdir="$HOME/.local/lib"
--localstatedir="$HOME/.local/var"
--mandir="$HOME/.local/share/man"
--with-gnutls=ifavailable
--with-tree-sitter=ifavailable
--with-native-compilation # No need for this on Emacs 30, it is the default if libgccjit is available
--with-xinput2
--without-compress-install
--with-modules
--without-libotf
--without-m17n-flt
# Beware https://debbugs.gnu.org/cgi/bugreport.cgi?bug=25228
# dconf and gconf break font settings you set in ~/.emacs.
# If you insist you'll need to read that bug report in *full*.
# Good luck!
--without-gconf
# ctags/etags may be provided by other packages, e.g, universal-ctags
--program-transform-name='s/\([ec]tags\)/\1.emacs/'
)
if [[ "${USE_CLANG}" == "YES" ]]; then
config_options+=('--enable-autodepend')
fi
if [[ "${LINK_TIME_OPTIMIZATION}" == "YES" ]]; then
config_options+=('--enable-link-time-optimization')
fi
if [[ "${AOT_ELISP}" == "YES" ]]; then
config_options+=('--with-native-compilation=aot')
fi
if [[ "${UI}" == "LUCID" ]]; then
config_options+=('--with-x-toolkit=lucid' '--with-xft' '--with-xaw3d' '--without-cairo')
elif [[ "${UI}" == "GTK3" ]]; then
config_options+=('--with-x-toolkit=gtk3' '--without-xaw3d')
elif [[ "${UI}" == "PGTK" ]]; then
config_options+=('--with-pgtk' '--without-xaw3d' '--without-gsettings')
fi
if [[ "${XWIDGETS}" == "YES" ]]; then
config_options+=('--with-xwidgets')
fi
if [[ "${ALSA}" == "YES" ]]; then
config_options+=('--with-sound=alsa')
else
config_options+=('--with-sound=no')
fi
# ===================================================================
../configure "${config_options[@]}"
make bootstrap
# -------------------------------------------------------------------
# Or use "make" rather than "make bootstrap":
# > make
# Using "make" instead of "make bootstrap" enables incremental
# compiling. Less time recompiling. Yay! But you may
# need to use bootstrap sometimes to unbreak the build.
# Just add it to the command line.
#
# Please note that incremental compilation implies that you
# are reusing your src directory!
#
# You may need to run this if 'loaddefs.el' files become corrupt.
# cd "${src_dir}/lisp"
# make autoloads
# cd ../build
# -------------------------------------------------------------------
if [[ "${MAKE_TRAMPOLINES}" == "YES" ]]; then
make trampolines
fi
# Optional documentation formats.
if [[ "${MAKE_DOCS_HTML}" == "YES" ]]; then
make html
fi
if [[ "${MAKE_DOCS_PDF}" == "YES" ]]; then
make pdf
fi
}
emacs-install() {
cd "${src_dir}/build" || exit 1
make PREFIX="${HOME}/.local/" install
# Install Emacs terminal command
if [[ ! -f "${HOME}/.local/bin/nemacs" ]]; then
printf '#!/usr/bin/bash -e\n\n[[ -x $HOME/.local/bin/emacs ]] && $HOME/.local/bin/emacs -nw $*' >"${HOME}/.local/bin/nemacs"
chmod a+x "${HOME}/.local/bin/nemacs"
fi
# Install optional documentation formats
if [[ $MAKE_DOCS_HTML == "YES" ]]; then make PREFIX="${HOME}/.local/" install-html; fi
if [[ $MAKE_DOCS_PDF == "YES" ]]; then make PREFIX="${HOME}/.local/" install-pdf; fi
}
emacs-build-and-install() {
echo "Preparing the build"
emacs-prepare
echo "Building Emacs"
emacs-build
echo "Installing Emacs"
emacs-install
}
emacs-build-and-install
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment