Compiling Emacs on MacOS

PSA: Don't do this

Just use emacs-plus. That does everything these notes do, but better.

Git Clone

git clone git://git.sv.gnu.org/emacs.git
cd emacs

Install Prerequisites

brew install libxml2
brew install librsvg
brew install imagemagick
brew install jansson

Provide path to libxml headers

Assuming you have already run brew install libxml2 from above:

prefix=$(brew --prefix)
export PKG_CONFIG_PATH="$prefix/lib/pkgconfig:$prefix/opt/libxml2/lib/pkgconfig"

Autogen

./autogen.sh

Configure

The configure script provides many options (run ./configure --help to see them all). You can just run ./configure and it will choose sensible defaults, printing out a summary of all the options it used at the end.

On MacOS, use the --with-xwidgets in order to use the a built-in browser. Great for live HTML previewing.

If imagemagick is installed, --with-imagemagick allows for some extra features for displaying images in Emacs.

./configure \
 --with-xwidgets \
 --with-imagemagick \
 --without-dbus \
 --with-json

Compile

Now run make bootstrap. The -j is optional; it allows make to run recipies in parllel, which speeds things up. This command will take 10-15 minutes.

make bootstrap -j

Question: What is the difference between make bootstrap and make? One thing: when running make bootstrap I need to have PKG_CONFIG_PATH set, but when just doing a make I don't. What else?

make -j
make install

After a make install, the executable is located at ./nextstep/Emacs.app/Contents/MacOS/Emacs.

MacOS recognizes the directory ./nextstep/Emacs.app as an "Application", so from the Finder, you can just double-click that directory to launch Emacs.

Add Icon to Dock

Just open Emacs.app (by double-clicking on the ./nextstep/Emacs.app/ directory in Finder), and that will put an icon in the dock. Then, pin the icon in the dock.

Verify Features

Once Emacs is running, check whether these features were properly enabled.

(image-type-available-p 'png)
(image-type-available-p 'svg)
(image-type-available-p 'imagemagick)

Debugging

$ lldb
(lldb) target create "nextstep/Emacs.app/Contents/MacOS/Emacs"
Current executable set to '/Users/chris.clark/Projects/emacs/nextstep/Emacs.app/Contents/MacOS/Emacs' (x86_64).
(lldb) run

To debug problems during running the init.el file, run $EMACS --debug-init.

Resources

Emacs for OSX https://github.com/caldwell/build-emacs

Similar to Emacs for OSX, but supports arbitrary git tags https://github.com/jimeh/build-emacs-for-macos

Homebrew emacs formula https://github.com/Homebrew/homebrew-core/blob/master/Formula/emacs.rb

Homebrew emacs-plus formula, which has a few more patches https://github.com/d12frosted/homebrew-emacs-plus

EmacsWiki Building Emacs on MacOS https://www.emacswiki.org/emacs?action=browse;oldid=EmacsOnMacOS;id=EmacsForMacOS

ARCHIVED: Native Compilation

Do things in this section if you want to compile Emacs --with-native-compilation.

NOTE 1: After a lot of struggle, I got this sort of working, but eventually gave up on native compilation. Some of the beauty of hacking on interpreted languages is not having to deal with compilation.

NOTE 2: Next time, probably best to use: https://github.com/jimeh/build-emacs-for-macos

Get libgccjit:

brew install libgccjit

Upgate the homebrew formula for gcc as described here: https://gist.github.com/AllenDang/f019593e65572a8e0aefc96058a2d23e

Then, Install gcc (I've heard clang works as well).

brew install gcc --build-from-source --force

You will now have a program on you $PATH called gcc-11. For some reason (why?) brew does not link gcc to gcc-11.

  • Do NOT manually create that link (say, by doing something like ln -s /usr/local/bin/gcc-11 /usr/local/bin/gcc). When I tried, it caused the following error during the ./configure step of building Emacs:

    checking for AppKit/AppKit.h... no
    configure: error: The include files (AppKit/AppKit.h etc) that
    are required for a Nextstep build are missing or cannot be compiled.
    Either fix this, or re-configure with the option '--without-ns'.
    

    Why does that happen?

Now, we have to tell Emacs which gcc to use and link some extra stuff.

gccVersion=$(brew info gcc --json | jq -r '.[].installed[].version')
gccMajorVersion=$(echo $gccVersion | cut -d "." -f 1)
export CFLAGS="-I/usr/local/Cellar/gcc/$gccVersion/include"
export CC="/usr/local/bin/gcc-$gccMajorVersion"
export LDFLAGS="-I/usr/local/Cellar/gcc/$gccVersion/lib/gcc/$gccMajorVersion -I/usr/local/Cellar/gcc/$gccVersion/include"
export LIBRARY_PATH="/usr/local/Cellar/gcc/$gccVersion/lib/gcc/$gccMajorVersion"

Now when running ./configure in the next section, add the --with-native-compilation flag.

When opening Emacs, the LIBRARY_PATH env var has to be set inside of Emacs. That means, start Emacs from the same terminal window where you set that $LIBRARY_PATH env var, so Emacs inherits it. If, instead, you start Emacs from a pinned Dock icon, Emacs won't have LIBRARY_PATH set, and you'll see an error like:

ld: library not found for -lgcc_ext.10.5
libgccjit.so: error: error invoking gcc driver

Notes/Questions

I think the LIBRARY_PATH env var only needs to be set in Emacs the first time it starts (?). Try pulling new packages and see if they are properly compiled when that env var isn't set.

Does LIBRARY_PATH need to be set when compiling Emacs, or only when starting Emacs?

Does this stuff have to happen before running the ./autogen.sh script?