The compile-angel package automatically byte-compiles and native-compiles Emacs Lisp libraries. It offers:
(compile-angel-on-load-mode)
: A global mode that compiles .el files before they are loaded.(compile-angel-on-save-local-mode)
: A local mode that compiles .el files whenever the user saves them.The compile-angel modes speed up Emacs by ensuring all libraries are byte-compiled and native-compiled. Byte-compilation reduces the overhead of loading Emacs Lisp code at runtime, while native compilation optimizes performance by generating machine code specific to your system.
The compile-angel author was previously an auto-compile user but encountered an issue where several .el files were not being compiled by auto-compile (see the explanation below), resulting in Emacs performance degradation due to the lack of native compilation. After extensive experimentation and research, the author developed compile-angel to address this problem. The compile-angel package guarantees that all .el files are both byte-compiled and native-compiled, which significantly speeds up Emacs.
After extensive experimentation and research, the compile-angel
author created the package to solve this problem. The compile-angel
package ensures that all .el
files are consistently byte-compiled and native-compiled, significantly improving Emacs performance.
Table of Contents
Because you are likely running a significant amount of interpreted, slow Elisp code that Emacs did not compile automatically. Ensuring that Elisp is native-compiled significantly improves Emacs' performance. Unfortunately, functions like package-install and package-recompile-all do not compile .el files that were not installed using package.el. Since these files are not byte-compiled, the Emacs JIT compiler does not native-compile them either, as a byte-compiled file signals the JIT compiler to perform native compilation. In contrast, compile-angel modes ensure that all loaded .el
files are compiled transparently, regardless of whether they are part of a package.
It is highly recommended to set the following variables at the very beginning of your early-init.el:
;; Ensure Emacs loads the most recent byte-compiled files.
(setq load-prefer-newer t)
;; Ensure JIT compilation is enabled for improved performance by
;; native-compiling loaded .elc files asynchronously
(setq native-comp-jit-compilation t)
(setq native-comp-deferred-compilation t) ; Deprecated in Emacs > 29.1
Additionally, ensure that native compilation is enabled:
This should return t: (native-comp-available-p)
To install compile-angel
from MELPA:
If you haven't already done so, add MELPA repository to your Emacs configuration.
Add the following code at the very beginning of your init.el file, before all other packages:
(use-package compile-angel
:ensure t
:demand t
:custom
(compile-angel-verbose nil)
:config
(compile-angel-on-load-mode)
(add-hook 'emacs-lisp-mode-hook #'compile-angel-on-save-local-mode))
Below are a few interesting options:
;; Ensure that quitting only occurs once Emacs finishes native compiling,
;; preventing incomplete or leftover compilation files in `/tmp`.
(setq native-comp-async-query-on-exit t)
(setq confirm-kill-processes t)
;; Show buffer when there is a warning.
;; (NOT RECOMMENDED, except during development).
(setq compile-angel-verbose t)
(setq warning-minimum-level :warning)
(setq byte-compile-verbose t)
(setq byte-compile-warnings t)
(setq native-comp-async-report-warnings-errors t)
(setq native-comp-warning-on-missing-source t)
;; Non-nil means to native compile packages as part of their installation.
(setq package-native-compile t)
You can make compile-angel exclude specific .el
files by adding regular expressions to compile-angel-excluded-files-regexps
.
For instance, to prevent compile-angel from compiling .dir-config.el files (the dir-config package) and .dir-locals.el files, add the following to your configuration:
(setq compile-angel-excluded-files-regexps '("/\\.dir-config\\.el$"
"/\\.dir-locals\\.el$" ))
You can control whether compile-angel performs byte-compilation or native-compilation of your .el files by setting the following variables in your configuration:
compile-angel-enable-byte-compile
: Set this variable to t
to enable byte-compilation. When enabled, compile-angel will generate .elc files for your .el files, making them load faster by converting them into bytecode. Set it to nil
to disable byte-compilation.compile-angel-enable-native-compile
: Set this variable to t
to enable native-compilation, which generates machine code for supported systems, further improving performance. Set it to nil
to disable native-compilation.Example configuration:
;; Enable both byte-compilation and native-compilation (default)
(setq compile-angel-enable-byte-compile t)
(setq compile-angel-enable-native-compile t)
The package-recompile-all function is effective for recompiling files within packages, but it misses other files that are not part of a package.
In the compile-angel author's configuration, for example, package-recompile-all skipped most of the local packages loaded using use-package with :ensure nil or require. Additionally, package-recompile-all does not compile transparently; the user must manually run it and wait for it to complete.
The compile-angel package, on the other hand, transparently compiles all packages without any user intervention. The user simply needs to enable (compile-angel-on-load-mode).
Jonas Bernouli, the author of auto-compile, has made some design decisions that prevent it from guaranteeing that all .el packages are byte-compiled and native-compiled. For example, if the user deletes all the .elc files or if the .el files have never been compiled before, auto-compile won't recompile them. Here is a quote from Jonas Bernouli, aka u/tarsius_, the auto-compile author (from this discussion):
Both [autocompile] modes only ever re-compile a source file when the respective byte code file already exists but is outdated. Otherwise they do not compile the source file. By "otherwise" I mean if:
- The .elc exists but is newer than the corresponding .el, OR
- The *.elc does not exist. In both cases the source file is not compiled, by design.
This is one of the reasons why opening an issue or submitting a pull request regarding the auto-compile issue above is pointless, as Jonas Bernouli is unlikely to merge it due to his design decision.
Here are the main differences between compile-angel and auto-compile:
.el
files loaded using load and require, also handles files that auto-compile misses, using the after-load-functions
hook. This ensures that all files are byte-compiled and native-compiled.The compile-angel Emacs package has been written by James Cherti and is distributed under terms of the GNU General Public License version 3, or, at your choice, any later version.
Copyright (C) 2024 James Cherti
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program.
Other Emacs packages by the same author: