How to Share Your Emacs Configuration Between Different Machines (and Architectures) with Native Compilation

EDIT:
Important! This was always a very specific solution to a very specific issue. However, starting from Emacs 30, it will no longer work or have any beneficial effects.
From Emacs 30 onward, .eln
files are linked per machine, meaning
the eln-cache
directory will automatically include a subfolder based
on the comp-abi-hash
variable and no adjustments from the user side
are needed.
For more details, see this discussion: Bug #76586.
TL;DR: Do not use these hacks anymore.
How to Share Your Emacs Configuration Between Different Machines (and Architectures) with Native Compilation
If you use Emacs on multiple machines, especially ones running
different architectures or operating systems, sharing your Emacs
configuration across those machines can become tricky. Add native
compilation (introduced in Emacs 28) to the mix, and you might run
into conflicts when Emacs tries to reuse compiled .eln
files between
machines.
Fortunately, with a bit of smart configuration, you can make Emacs
share your configuration while keeping native compilation enabled for
each machine. In this post, I'll show you how to set up your Emacs so
that native compilation caches (.eln
files) are kept separate for
each machine. We'll also discuss why this is important and what your
directory structure will look like.
Why Is This Important?
Emacs uses native compilation to compile Elisp files into optimized
.eln
binaries, which are architecture and system-dependent. If you
share your Emacs configuration across machines without accounting for
this, you may encounter issues:
-
Conflicting
.eln
files: A.eln
file compiled for a Linux machine might not work on a macOS machine. -
Unnecessary recompilations: Emacs may attempt to recompile packages on each startup, which can slow things down and clutter your
eln-cache
directory.
By separating the native compilation cache for each machine, you ensure:
• Faster startup times since Emacs doesn't recompile already-compiled code.
• A cleaner and more predictable setup across machines.
The Solution: Machine-Specific eln-cache
Directories
To keep .eln
files organized and avoid conflicts, you can configure
Emacs to use a machine-specific eln-cache
directory. Here's the
configuration snippet to add into your early-init.el
:
;;; Native Compile Settings
;; I use a <emacs-default-dir>/eln-cache-<machine-hostname>/ dir to store
;; my different machines' eln compiled code. This allows the same config
;; to be used on several machines without conflicts.
;; This is added in early-init.el to prevent unwanted recompilations.
(when (featurep 'native-compile)
;; Set the right directory to store the native compilation cache
(let ((path (expand-file-name (concat "eln-cache-" (system-name) "/") user-emacs-directory)))
(setq-default native-comp-eln-load-path (list path)
native-compile-target-directory path)
(startup-redirect-eln-cache path))
(setq-default native-comp-async-report-warnings-errors nil ;; Silence compiler warnings as they can be disruptive
native-comp-jit-compilation t ;; Enable async native compilation
package-native-compile t))) ;; Compile installed packages
What Does This Code Do?
-
(system-name):
Retrieves the hostname of the machine. This is used to create a unique directory for each machine's eln-cache. -
expand-file-name:
Combines the Emacs configuration directory (user-emacs-directory) with the machine-specificeln-cache-<hostname>
folder. -
native-comp-eln-load-path
andnative-compile-target-directory:
Set the paths for Emacs to store and load the compiled.eln
files. -
startup-redirect-eln-cache:
Ensures Emacs uses the specified eln-cache directory right from startup.
Optional settings:
• native-comp-async-report-warnings-errors:
Silences disruptive compiler warnings.
• native-comp-jit-compilation:
Enables Just-In-Time (JIT) native
compilation for faster execution.
• package-native-compile:
Ensures all installed packages are
natively compiled.
By placing this in your early-init.el
, you make sure Emacs sets up
the eln-cache
directory before it starts loading packages or
recompiling files.
Folder Structure Example
Let's say you have two machines, with the following hostnames:
• debian:
A Linux workstation.
• macbook:
A macOS laptop.
With the above configuration, your Emacs directory structure will look like this:
~/.emacs.d/
|-- early-init.el
|-- init.el
|-- eln-cache-debian/ # Cache for 'debian'
| |-- abcdef01-abcdefgh01.eln
| |-- xyz12345-xyzabc123.eln
|
|-- eln-cache-macbook/ # Cache for 'macbook'
|-- abcdef01-abcdefgh01.eln
|-- pqr67890-pqrxyz678.eln
Setting Up for a New Machine
If you're setting up Emacs on a new machine:
-
Clone or copy your shared Emacs configuration (e.g., from GitHub).
-
Make sure the above snippet is in your early-init.el.
-
Start Emacs. It will automatically create a new
eln-cache-<hostname>
directory and begin compiling packages natively for the current machine.
Conclusion
Sharing Emacs configurations across machines doesn't have to be a hassle, even when using native compilation. By directing Emacs to use machine-specific eln-cache directories, you can:
• Avoid conflicts caused by incompatible .eln files.
• Speed up startup times by preventing unnecessary recompilations.
• Maintain a clean and organized Emacs setup.
I hope with the provided configuration, you can easily manage Emacs on multiple machines—whether you're switching between Linux, macOS, or different hardware architectures.
Happy hacking!
Edit
2025-02-26: Added the "do not use this" note above the header.