Skip to content

Instantly share code, notes, and snippets.

@abidanBrito
Last active May 11, 2026 22:32
Show Gist options
  • Select an option

  • Save abidanBrito/2b5e447f191bb6bb70c9b6fe6f9e7956 to your computer and use it in GitHub Desktop.

Select an option

Save abidanBrito/2b5e447f191bb6bb70c9b6fe6f9e7956 to your computer and use it in GitHub Desktop.
Build GNU Emacs from source.
#!/usr/bin/env bash
## Author: Abidán Brito
## This script builds GNU Emacs 29.1 with support for native elisp compilation,
## tree-sitter, libjansson (C JSON library), pure GTK and mailutils.
# Exit on error and print out commands before executing them.
set -euxo pipefail
# Let's set the number of jobs to something reasonable; keep 2 cores
# free to avoid choking the computer during compilation.
JOBS=`nproc --ignore=2`
# Clone repo locally and get into it.
git clone --depth 1 --branch emacs-29 git://git.savannah.gnu.org/emacs.git
pushd emacs
# Get essential dependencies.
sudo apt install -y build-essential \
texinfo \
libgnutls28-dev \
libjpeg-dev \
libpng-dev \
libtiff5-dev \
libgif-dev \
libxpm-dev \
libncurses-dev \
libgtk-3-dev \
libtree-sitter-dev \
libmagick++-dev \
#libwebkit2gtk-4.1-dev \
# Get dependencies for gcc-10 and the build process.
sudo apt update -y
sudo apt install -y gcc-11 \
g++-11 \
libgccjit0 \
libgccjit-11-dev \
autoconf \
# Get dependencies for fast JSON.
sudo apt install -y libjansson4 libjansson-dev
# Get GNU Mailutils (protocol-independent mail framework).
sudo apt install -y mailutils
# Enable source packages and get dependencies for whatever
# Emacs version Ubuntu supports by default.
#
# Taken from here:
# https://www.masteringemacs.org/article/speed-up-emacs-libjansson-native-elisp-compilation
#sudo sed -i 's/# deb-src/deb-src/' /etc/apt/sources.list \
# && apt update \
# && apt build-dep -y emacs
# Stop debconf from complaining about postfix nonsense.
DEBIAN_FRONTEND=noninteractive
# Needed for compiling libgccjit or we'll get cryptic error messages.
export CC=/usr/bin/gcc-11 CXX=/usr/bin/g++-11
# Configure and run.
# NOTE(abi): binaries should go to /usr/local/bin by default.
#
# Options:
# --with-native-compilation -> use the libgccjit native compiler
# --with-pgtk -> better font rendering
# --with-x-toolkit=gtk3 -> widgets toolkit
# --with-tree-sitter -> syntax parsing
# --with-wide-int -> larger file size limit
# --with-json -> fast JSON
# --with-gnutls -> TLS/SSL
# --with-mailutils -> e-mail
# --without-pop -> no pop3 (insecure channels)
# --with-cairo -> vector graphics backend
# --with-imagemagick -> raster images backend
./autogen.sh \
&& ./configure \
--with-native-compilation \
--with-pgtk \
--with-x-toolkit=gtk3 \
--with-tree-sitter \
--with-wide-int \
--with-json \
--with-modules \
--without-dbus \
--with-gnutls \
--with-mailutils \
--without-pop \
--with-cairo \
--with-imagemagick \
# Other interesting compilation options:
#
#--prefix="" # output binaries location
#--with-x-toolkit=lucid # supposedly more stable
#--with-xwidgets
# Compiler flags:
# -O2 -> Turn on a bunch of optimization flags. There's also -O3, but it increases
# the instruction cache footprint, which may end up reducing performance.
# -pipe -> Reduce temporary files to the minimum.
# -mtune=native -> Optimize code for the local machine (under ISA constraints).
# -march=native -> Enable all instruction subsets supported by the local machine.
# -fomit-frame-pointer -> Small functions don't need a frame pointer (optimization).
#
# https://lemire.me/blog/2018/07/25/it-is-more-complicated-than-i-thought-mtune-march-in-gcc/
CFLAGS="-O2 -pipe -mtune=native -march=native -fomit-frame-pointer"
# Build.
# NOTE(abi): NATIVE_FULL_AOT=1 ensures native compilation ahead-of-time for all
# elisp files included in the distribution.
make -j${JOBS} NATIVE_FULL_AOT=1 \
&& make install
# Return to the original path.
popd
#!/usr/bin/env bash
## Author: Abidán Brito
## This script builds GNU Emacs 30.1 with support for native elisp compilation,
## tree-sitter, libjansson (C JSON library), pure GTK and mailutils on Arch Linux
## for Wayland.
# Exit on error and print out commands before executing them.
set -euxo pipefail
# Let's set the number of jobs to something reasonable; keep 2 cores
# free to avoid choking the computer during compilation.
JOBS=$(nproc --ignore=2)
# Clone the repo locally (no blob checkout) and get into it.
git clone --depth 1 --branch emacs-30 git://git.savannah.gnu.org/emacs.git
pushd emacs
# Get essential dependencies.
sudo pacman -S --needed \
base-devel \
texinfo \
gnutls \
libjpeg-turbo \
libpng \
libtiff \
libwebp \
giflib \
libxpm \
librsvg \
ncurses \
gtk3 \
imagemagick \
glib2 \
libxml2 \
sqlite \
cairo
# Get Wayland-specific dependencies.
sudo pacman -S --needed \
wayland \
wayland-protocols \
gtk-layer-shell
# Get dependencies for gcc and the build process.
sudo pacman -S --needed \
gcc \
libgccjit \
autoconf
# Get dependencies for fast JSON.
sudo pacman -S --needed jansson
# Get GNU Mailutils (protocol-independent mail framework).
sudo pacman -S --needed mailutils
# Get the tree-sitter syntax parsing engine.
sudo pacman -S --needed tree-sitter
# Get an OpenType font shaping engine (for ligatures).
sudo pacman -S --needed harfbuzz
# Use system GCC
# NOTE(abi): needed when compiling with libgccjit or we'll get cryptic error messages.
export CC=/usr/bin/gcc CXX=/usr/bin/g++
# Configure and run.
# NOTE(abi): binaries should go to /usr/local/bin by default.
#
# Options:
# --prefix -> where to install Emacs to
# --with-native-compilation -> use libgccjit for native elisp AOT compilation
# --with-pgtk -> pure GTK interface (no X11, better font rendering)
# --with-wayland -> force Wayland backend
# --with-tree-sitter -> better syntax highlighting/parsing
# --with-json -> libjansson for JSON parsing
# --with-imagemagick -> raster images backend
# --with-cairo -> vector graphics backend
# --with-mailutils -> mail client integration
# --without-pop -> no POP3 (insecure channels)
# --with-gnutls -> secure HTTPS connections (TLS/SSL)
# --with-wide-int -> larger file size limit
# --with-modules -> dynamic module support
# --without-dbus -> skip D-Bus IPC
#
# Flags:
# -O2 -> Turn on a bunch of optimization flags. There's also -O3, but it increases
# the instruction cache footprint, which may end up reducing performance.
# -pipe -> Reduce temporary files to the minimum.
# -mtune=native -> Optimize code for the local machine (under ISA constraints).
# -march=native -> Enable all instruction subsets supported by the local machine.
# -fomit-frame-pointer -> Small functions don't need a frame pointer (optimization).
#
# https://lemire.me/blog/2018/07/25/it-is-more-complicated-than-i-thought-mtune-march-in-gcc/
./autogen.sh \
&& ./configure \
--with-native-compilation \
--with-pgtk \
--with-wayland \
--with-tree-sitter \
--with-json \
--with-sqlite3 \
--with-harfbuzz \
--with-wide-int \
--with-modules \
--without-dbus \
--with-gnutls \
--with-mailutils \
--with-xml2 \
--without-pop \
--with-cairo \
--with-jpeg \
--with-png \
--with-tiff \
--with-gif \
--with-rsvg \
--with-imagemagick \
CFLAGS="-O2 -pipe -mtune=native -march=native -fomit-frame-pointer"
# Build.
make -j${JOBS} NATIVE_FULL_AOT=1 \
&& sudo make install
# Return to the original path.
popd
@abidanBrito

Copy link
Copy Markdown
Author

FYI you no longer need --with-json starting in Emacs 31.

I'll keep an eye out, thanks for the heads up! I’ve just added a new version for Emacs 30, targeting a pure Wayland setup on Arch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment