UP | HOME

▼ 本文更新于 [2026-01-20 周二 11:29]

emacs-使用compile-angel按需原生编译el文件


自从28.1开始,Emacs就有了原生编译(Native compilation)的功能。相较于编译为 elc 的字节编译(Byte compilation),原生编译性能更好:

与字节编译代码不同,原生编译的 Lisp 代码直接由机器的硬件执行,因此能够以主机 CPU 所能提供的全速运行。由此带来的速度提升通常取决于 Lisp 代码的功能,但通常比相应的字节编译代码快 2.5 到 5 倍。

由于原生代码通常在不同系统之间不兼容,因此原生编译的代码无法从一台机器传输到另一台机器使用,它只能在生成它的同一台机器或非常相似的机器(具有相同的 CPU 和运行时库)上使用。原生编译代码的可移植性与共享库( .so 或 .dll 文件)相同。

——Native Compilation (GNU Emacs Lisp Reference Manual)

接下来要介绍的 compile-angel 包,可以「确保所有加载的 .el 文件都能透明地编译,无论它们是否属于某个包。」

1. 官方推荐设置

1.1. 在 early-init.el 中(没有则创建该文件)

early-init.el 文件的最开头设置以下变量:

;; 确保 Emacs 加载最新的字节编译文件。
(setq load-prefer-newer t)

;; 通过将 `native-comp-jit-compilation` 设置为 t,使 Emacs 异步原生编译 .elc 文件。
;; `native-comp-jit-compilation' to t.
(setq native-comp-jit-compilation t)
(setq native-comp-deferred-compilation native-comp-jit-compilation)  ; Deprecated

1.2. 在 init.el 文件中

我们通过melpa下载这个包,如何安装配置melpa不在这里赘述。
将以下代码添加至 init.el 文件的最开头,在所有其他包之前:

(use-package compile-angel
  :ensure t
  :demand t
  :config
  ;; 将 `compile-angel-verbose' 设为 nil 以禁用 compile-angel 消息。
  ;; (设为 nil 时,compile-angel 不会显示正在编译的文件。)
  (setq compile-angel-verbose t)

  ;; 如果取消了下面这行的注释,就可以在保存 Elisp 文件时自动编译
  ;; (add-hook 'emacs-lisp-mode-hook #'compile-angel-on-save-local-mode)

  ;; 以下指令可防止 compile-angel 编译您的初始化文件。
  ;; 若您选择从 `compile-angel-excluded-files` 中移除
  ;; 此项并编译您的预/后初始化文件,请确保理解其潜在
  ;; 影响并彻底测试您的代码。例如,如果您正在使用
  ;; `use-package` 宏,则需要在初始化文件顶部显式添加:
  ;; (eval-when-compile (require 'use-package))
  (push "/init.el" compile-angel-excluded-files)
  (push "/early-init.el" compile-angel-excluded-files)

  ;; 一个全局模式,在通过 `load` 或
  ;; `require` 加载 .el 文件之前编译它们。
  (compile-angel-on-load-mode 1))

1.3. 补充说明

如果你还有其他的配置文件,比如我另外维护了一个自动生成的 config.el 文件,那么也需要把这个文件加入排除列表。注意,这些排除列表需要在 compile--angel-on-load-mode 之前执行。

;; 在启用 `compile-angel-on-load-mode` 之前运行以下代码
(push "/config.el" compile-angel-excluded-files)

;; 一些测试文件和本地路径文件不需要被编译
(push ".dir-locals.el" compile-angel-excluded-files)
(push "test.el" compile-angel-excluded-files)

;; 在此处运行:(compile-angel-on-load-mode 1)

1.4. 可选项

原作者推荐的其他可选项。我个人是关闭了字节编译,因为会生成难以处理的elc文件,不如直接在每个设备用原生编译的eln了。

;; 确保仅在 Emacs 完成原生编译后才退出,
;; 防止在 `/tmp` 目录中留下不完整或残留的编译文件。
(setq native-comp-async-query-on-exit t)
(setq confirm-kill-processes t)

;; 非空值表示在安装包时进行原生编译。
(setq package-native-compile t)

;; 排除 custom-file、recentf 和 savehist 文件
;;
;; 确保使用 `require`、`use-package` 或其他包管理器加载 compile-angel,
;; 因为 compile-angel-excluded-files 是在包加载后声明的。
;; 确保在处理之前更新 `savehist-file` `recentf-save-file` `custom-file`的值
(with-eval-after-load "savehist"
  (push (concat "/" (file-name-nondirectory savehist-file))
        compile-angel-excluded-files))
(with-eval-after-load "recentf"
  (push (concat "/" (file-name-nondirectory recentf-save-file))
        compile-angel-excluded-files))
(with-eval-after-load "cus-edit"
  (when (stringp custom-file)
    (push (concat "/" (file-name-nondirectory custom-file))
          compile-angel-excluded-files)))

;; 启用字节编译和原生编译(默认为t)
(setq compile-angel-enable-byte-compile nil)
(setq compile-angel-enable-native-compile t)

;; 在以上设置后启用 (compile-angel-on-load-mode) 

© Published by Emacs 31.0.50 (Org mode 9.8-pre) | RSS English-Index