Gcc Emacs is the latest attempt to
bring native code compilation to Emacs's elisp. It uses gcc's
libgccjit to produce native code binaries for the current system from
elisp.
Installation
Installation on my arch linux system was quite simple, but things turned
out to be a bit less simple on macOS.
I initially tried to use
this
guide, but needed to perform several tweaks to get things working.
The gist suggests installing gcc from homebrew, with the following
modification to
/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/gcc.rb
:
diff --git a/Formula/gcc.rb b/Formula/gcc.rb
index 1bd636d496..03ad124218 100644
--- a/Formula/gcc.rb
+++ b/Formula/gcc.rb
@@ -53,7 +53,7 @@ class Gcc < Formula
# - Ada, which requires a pre-existing GCC Ada compiler to bootstrap
# - Go, currently not supported on macOS
# - BRIG
- languages = %w[c c++ objc obj-c++ fortran]
+ languages = %w[c c++ objc obj-c++ fortran jit]
osmajor = `uname -r`.split(".").first
pkgversion = "Homebrew GCC #{pkg_version} #{build.used_options*" "}".strip
@@ -73,6 +73,7 @@ class Gcc < Formula
--with-system-zlib
--with-pkgversion=#{pkgversion}
--with-bugurl=https://github.com/Homebrew/homebrew-core/issues
+ --enable-host-shared
]
# Xcode 10 dropped 32-bit support
and then simply running brew install gcc --build-from-source --force
.
This didn't quite work to start with, homebrew, by default, will want
to "update" the gcc formula back to the original, however, this can be
fixed by simply running
env HOMEBREW_NO_AUTO_UPDATE=1 brew install gcc --build-from-source --force
instead.
The guide also neglected to mention that you need jansson
installed
for the --with-json
configure option to work. The version of jansson
provided by brew install jansson
The gist is, additionally, out of date, so I had to edit its references
to gcc 10.1.0 to 10.2.0. It also additionally assumes that CC
is set
to the homebrew-installed gcc. I personally rectified that by manually
pointing my gcc symlink to the homebrew provided gcc.
Attempting to compile with the provided build.sh
also additionally
caused the configure script to scream about AppKit.h
being available,
but not usable. This was rectified by running temporarily setting CC
to /usr/bin/clang
while running the configure script.
After the build and install completed, emacs was complaining about not
being able to find eln
files, which I was able to fix, somewhat
jankily, by copying the native-lisp
directory in the build folder to
/usr/local
.
All-in-all, this is the final version of the modified build.sh
that I
wound up using:
#!/bin/sh
# native-comp optimization
export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:${PATH}"
export CFLAGS="-I/usr/local/Cellar/gcc/10.2.0/include -O2 -march=native"
export LDFLAGS="-L/usr/local/Cellar/gcc/10.2.0/lib/gcc/10 -I/usr/local/Cellar/gcc/10.2.0/include"
export LIBRARY_PATH="/usr/local/Cellar/gcc/10.2.0/lib/gcc/10:${LIBRARY_PATH:-}"
cd emacs || exit
git clean -xfd
echo ""
echo "autogen"
echo ""
./autogen.sh
echo ""
echo "configure"
echo ""
export CC=/usr/bin/clang
./configure \
--disable-silent-rules \
--enable-locallisppath=/usr/local/share/emacs/28.0.50/site-lisp \
--prefix=/usr/local/opt/gccemacs \
--without-dbus \
--without-imagemagick \
--with-mailutils \
--with-ns \
--with-json \
--disable-ns-self-contained \
--with-cairo \
--with-modules \
--with-xml2 \
--with-gnutls \
--with-rsvg \
--with-nativecomp
read -p "Press any key to resume ..."
# Ensure /usr/local/opt/gccemacs exists
rm -rf /usr/local/opt/gccemacs
mkdir /usr/local/opt/gccemacs
# Ensure the directory to which we will dump Emacs exists and has the correct
# permissions set.
libexec=/usr/local/libexec/emacs/28.0.50
if [ ! -d $libexec ]; then
sudo mkdir -p $libexec
sudo chown $USER $libexec
fi
echo ""
echo "make"
echo ""
export CC=gcc
make -j6
make install
rm -rf "/Applications/Gccemacs.app"
mv nextstep/Emacs.app "/Applications/Gccemacs.app"
rm -rf /usr/local/native-lisp/
cp -R native-lisp /usr/local
cd /usr/local/bin || exit
rm gccemacs
rm gccemacsclient
ln -s /usr/local/opt/gccemacs/bin/emacs ./gccemacs
ln -s /usr/local/opt/gccemacs/bin/emacsclient ./gccemacsclient
cd /Applications/Gccemacs.app/Contents || exit
ln -s /usr/local/opt/gccemacs/share/emacs/28.0.50/lisp .
I, personally, decided to name my binaries as gccemacs
, to allow
coexistence with regular emacs.
Impressions
The first start on Gcc Emacs is, well, brutal.
I don't know exactly how long it took to compile all my packages, as I
wound up leaving my desk to do some things around the house, and came
back an hour later to find it complete.
After the initial cost of compiling everything is paid, emacs is notably
snappier. My init time has dropped from 5.2 seconds to 4.1 seconds, and
there is no longer a noticeable hangup when a lazy loaded package kicks
in, and commands that were once painful to run, such as
helm-org-rifle
, are now much smoother and I no longer experience a
noticeable hang upon running them. I haven't actually experienced a
momentary hang since switching over.
I have not noticed any behavioral difference (besides speed) over
running regular emacs. straight.el
's native-comp support just
worked.
Gcc Emacs is going excellent so far, and I hope its path to master is
short and pleasant.