16.1 程序的加载方式

Emacs Lisp 提供了多种加载接口。例如, autoload 会为文件中定义的函数创建一个占位对象; 调用这个自动加载函数时,会加载对应文件以获取函数的实际定义(see 自动加载)。 require 会在文件尚未加载时加载它(see 功能)。 最终,这些功能都会调用 load 函数来完成实际加载工作。

Function: load filename &optional missing-ok nomessage nosuffix must-suffix

该函数查找并打开指定的 Lisp 代码文件,对其中所有表达式求值,然后关闭文件。

查找文件时,load 首先寻找名为 filename.elc 的文件(即文件名是 filename 附加扩展名 ‘.elc’)。 若该文件存在,且 Emacs 编译时启用了原生编译支持(see Lisp 本地代码编译), load 会尝试查找对应的 ‘.eln’ 文件; 若找到,则加载该文件而非 filename.elc。 否则,加载 filename.elc(并在后台启动原生编译以生成缺失的 ‘.eln’ 文件, 编译完成后再加载该文件)。 若不存在 filename.elcload 会查找名为 filename.el 的文件, 若存在则加载。 若 Emacs 编译时支持动态模块(see Emacs 动态模块), load 接下来会查找名为 filename.ext 的文件, 其中 ext 是系统相关的共享库扩展名(GNU 和 Unix 系统上为 ‘.so’)。 最后,若以上文件名均未找到,load 会查找无任何后缀的 filename 文件, 若存在则加载。 (load 函数对 filename 的处理逻辑较为简单: 极端情况下,若存在名为 foo.el.el 的文件,执行 (load "foo.el") 确实会找到它。)

如果自动压缩模式(默认启用)处于开启状态, 当 load 找不到文件时,会先搜索该文件的压缩版本,再尝试其他文件名。 若找到压缩版本,则解压缩并加载。 它会通过将 jka-compr-load-suffixes 中的每个后缀附加到文件名后, 来查找压缩版本。 该变量的值必须是字符串列表,其标准值为 (".gz")

若可选参数 nosuffixnil, 则 load 不会尝试 ‘.elc’ 和 ‘.el’ 后缀。 此时你必须指定精确的文件名,但如果自动压缩模式开启, load 仍会使用 jka-compr-load-suffixes 查找压缩版本。 通过指定精确文件名并将 nosuffix 设为 t, 可避免尝试 foo.el.el 这类文件名。

若可选参数 must-suffixnil, 则 load 要求所用文件名必须以 ‘.el’、‘.elc’(可附加压缩后缀) 或共享库扩展名结尾,除非文件名中包含显式的目录名。

若选项 load-prefer-newernil, 则在搜索后缀时,load 会选择修改时间最新的文件版本(‘.elc’、‘.el’ 等)。 这种情况下,即使存在 ‘.eln’ 原生编译文件,load 也不会加载它。

filename 是相对文件名(如 foobaz/foo.bar), load 会通过变量 load-path 搜索文件。 它将 filename 附加到 load-path 列出的每个目录后, 加载第一个找到的匹配文件。 仅当当前默认目录在 load-path 中指定时(nil 代表默认目录), 才会尝试该目录。 load 会先在 load-path 的第一个目录中尝试所有三种可能的后缀, 再在第二个目录中尝试所有三种后缀,依此类推。See 库搜索

无论最终找到的文件名和所在目录是什么, Emacs 都会将变量 load-file-name 的值设为该文件的完整名称。

若收到警告提示 foo.elcfoo.el 旧, 说明你应考虑重新编译 foo.el。See 字节编译

加载源文件(未编译)时,load 会执行字符集转换, 与 Emacs 访问该文件时的行为一致。See Coding Systems

加载未编译文件时,Emacs 会尝试展开文件中包含的所有宏(see )。 我们将此称为 立即宏展开(eager macro expansion)。 这种做法(而非延迟到相关代码运行时再展开) 能显著提升未编译代码的执行速度。 有时,由于循环依赖,宏展开无法完成。 最简单的例子是:你正在加载的文件引用了另一个文件中定义的宏, 而该文件又依赖于你正在加载的文件。 此时 Emacs 会抛出错误(提示 ‘因循环依赖跳过立即宏展开…’), 并给出问题详情。 你需要重构代码以避免这种情况。 加载编译文件不会触发宏展开,因为这一过程应已在编译时完成。See 宏与字节编译

加载过程中,除非 nomessagenil, 否则回显区会显示 ‘Loading foo...’ 和 ‘Loading foo...done’ 这类提示。 若加载的是原生编译的 ‘.eln’ 文件,提示信息会明确说明。

加载文件时出现的未处理错误会终止加载过程。 如果此次加载是因 autoload 触发, 加载过程中创建的所有函数定义都会被撤销。

load 找不到要加载的文件,通常会抛出 file-error 错误 (提示 ‘无法打开加载文件 filename’)。 但如果 missing-oknil,则 load 仅返回 nil

你可以通过变量 load-read-function 指定一个函数, 让 load 用该函数替代 read 来读取表达式。 详见下文。

若文件加载成功,load 返回 t

Command: load-file filename

该命令加载文件 filename。 若 filename 是相对文件名,则使用当前默认目录。 该命令不使用 load-path,也不会附加后缀, 但会查找压缩版本(若自动压缩模式启用)。 如果你需要精确指定要加载的文件名,可使用此命令。

Command: load-library library

该命令加载名为 library 的库。 除了交互式读取参数的方式不同外,其功能与 load 等效。 See Lisp Libraries in The GNU Emacs Manual

Variable: load-in-progress

当 Emacs 正在加载文件时,该变量值为非 nil;否则为 nil

Variable: load-file-name

当 Emacs 正在加载文件时,该变量的值是本节前文所述搜索过程中找到的文件名。

Variable: load-read-function

该变量为 loadeval-region 指定替代 read 的表达式读取函数。 该函数应像 read 一样接受一个参数。

默认情况下,该变量的值为 read。See 输入函数

相比使用该变量,更规范的方式是使用一个更新的特性: 将该函数作为 read-function 参数传递给 eval-region。 See Eval

关于 load 在 Emacs 构建过程中的使用方式,详见 Building Emacs


emacs

Emacs

org-mode

Orgmode

Donations

打赏

Copyright

© 2025 Jasper Hsu

Creative Commons

Creative Commons

Attribute

Attribute

Noncommercial

Noncommercial

Share Alike

Share Alike