17.2 字节编译函数

你可以使用 byte-compile 函数对单个函数或宏定义进行字节编译。 使用 byte-compile-file 可以编译整个文件, 使用 byte-recompile-directorybatch-byte-compile 可以编译多个文件。

有时,字节编译器会产生警告和/或错误信息 (详情参见see 编译器错误)。这些信息通常 记录在名为 *Compile-Log* 的缓冲区中, 该缓冲区使用编译模式。 See Compilation Mode in The GNU Emacs Manual。 但是,如果变量 byte-compile-debugnil, 错误信息会以 Lisp 错误的形式抛出 (see 错误)。

在打算进行字节编译的文件中编写宏调用时要格外小心。 由于宏调用在编译时展开,因此宏必须已经加载到 Emacs 中, 否则字节编译器无法正确处理。 通常的处理方式是使用 require 表达式, 指定包含所需宏定义的文件(参见see 功能)。 一般情况下,字节编译器不会对正在编译的代码求值, 但它会特殊处理 require 表达式,加载指定的库。 为了避免在用户 运行 编译后的程序时加载宏定义文件, 可以在 require 调用外层使用 eval-when-compile (参见see 编译时求值)。 更多细节参见see 宏与字节编译

内联(defsubst)函数则问题较少; 如果你在尚未知晓其定义时就编译对该函数的调用, 调用仍然可以正常工作,只是运行速度会慢一些。

Function: byte-compile symbol

该函数对 symbol 的函数定义进行字节编译, 并用编译后的定义替换原有定义。 symbol 的函数定义必须是函数的实际代码; byte-compile 不处理函数间接引用。 返回值是字节码函数对象,即 symbol 编译后的定义 (see 闭包函数对象)。

(defun factorial (integer)
  "Compute factorial of INTEGER."
  (if (= 1 integer) 1
    (* integer (factorial (1- integer)))))
⇒ factorial

(byte-compile 'factorial)
⇒
#[257
  "\211\300U\203^H^@\300\207\211\301^BS!_\207"
  [1 factorial] 4
  "Compute factorial of INTEGER.\n\n(fn INTEGER)"]

如果 symbol 的定义已经是字节码函数对象, byte-compile 不做任何操作并返回 nil。 它不会再次编译该符号的定义,因为原始 (未编译)代码已经被字节编译代码替换到符号的函数单元中。

byte-compile 的参数也可以是 lambda 表达式。 此时函数返回对应的编译代码,但不会将其保存到任何地方。

Command: compile-defun &optional arg

该命令读取光标所在的 defun 形式,对其编译,并对结果求值。 如果你对实际是函数定义的 defun 使用该命令, 效果是安装该函数的编译版本。

compile-defun 通常在回显区显示求值结果, 但如果 argnil,它会将结果 插入到当前缓冲区中被编译形式的后面。

Command: byte-compile-file filename

该函数将名为 filename 的 Lisp 代码文件编译为 字节码文件。输出文件名通过将后缀 ‘.el’ 改为 ‘.elc’ 得到; 如果 filename 不以 ‘.el’ 结尾, 则在末尾添加 ‘.elc’。

编译过程是每次读取输入文件中的一个形式。 如果是函数或宏定义,则写入编译后的函数或宏定义。 其他形式会被分批处理,然后每一批被编译并写入, 使得编译后的代码在文件被加载时执行。 读取输入文件时所有注释都会被丢弃。

如果没有错误,该命令返回 t,否则返回 nil。 交互调用时,它会提示输入文件名。

$ ls -l push*
-rw-r--r-- 1 lewis lewis 791 Oct  5 20:31 push.el

(byte-compile-file "~/emacs/push.el")
     ⇒ t

$ ls -l push*
-rw-r--r-- 1 lewis lewis 791 Oct  5 20:31 push.el
-rw-rw-rw- 1 lewis lewis 638 Oct  8 20:25 push.elc
Command: byte-recompile-directory directory &optional flag force follow-symlinks

该命令重新编译 directory(或其子目录)中 所有需要重新编译的 ‘.el’ 文件。 如果存在 ‘.elc’ 文件但比对应的 ‘.el’ 文件旧, 则该文件需要重新编译。

当某个 ‘.el’ 文件没有对应的 ‘.elc’ 文件时, flag 决定如何处理。 如果为 nil,该命令忽略这些文件。 如果为 0,则编译它们。 如果既不是 nil 也不是 0, 则询问用户是否编译每个此类文件, 并对每个子目录也进行询问。

交互使用时,byte-recompile-directory 会提示输入目录, flag 为前缀参数。

如果 forcenil, 该命令会重新编译所有存在 ‘.elc’ 文件的 ‘.el’ 文件。

该命令通常不会编译符号链接指向的 ‘.el’ 文件。 如果可选参数 follow-symlinksnil, 则符号链接的 ‘.el’ 文件也会被编译。

返回值不可预测。

Function: batch-byte-compile &optional noforc

该函数对命令行指定的文件运行 byte-compile-file。 该函数只能在 Emacs 的批处理执行中使用, 因为它在完成后会退出 Emacs。 某个文件中的错误不会阻止后续文件的处理, 但该文件不会生成输出文件, 且 Emacs 进程会以非零状态码退出。

如果 noforcenil, 该函数不会重新编译那些 ‘.elc’ 文件已是最新的文件。

$ emacs -batch -f batch-byte-compile *.el

emacs

Emacs

org-mode

Orgmode

Donations

打赏

Copyright

© 2025 Jasper Hsu

Creative Commons

Creative Commons

Attribute

Attribute

Noncommercial

Noncommercial

Share Alike

Share Alike