Emacs 动态模块(dynamic Emacs module) 是一种共享库,可为 Emacs Lisp 程序提供额外功能,与使用 Emacs Lisp 编写的包类似。
用于加载 Emacs Lisp 包的函数同样可以加载动态模块。系统通过文件名扩展名(也称 “后缀(suffix)”)识别动态模块,该后缀与平台相关。
该变量保存模块文件的文件名扩展名,其值与系统相关。 在 POSIX 系统上为 .so,macOS 上为 .dylib,MS-Windows 上为 .dll。
在 macOS 上,动态模块除了 .dylib 之外,也可以使用后缀 .so。
每个动态模块都应导出一个名为 emacs_module_init 的 C 可调用函数,Emacs 会在通过 load 或 require 加载模块时调用它。
模块还应导出一个名为 plugin_is_GPL_compatible 的符号,表明其代码基于 GPL 或兼容协议发布;
如果程序尝试加载未导出该符号的模块,Emacs 会报错。
如果模块需要调用 Emacs 函数,应通过 Emacs 发行版中附带的头文件 emacs-module.h 所定义并说明的 API(应用程序编程接口)实现。 See Writing Dynamically-Loaded Modules 查看编写模块时使用该 API 的详细信息。
模块可以创建 user-ptr 类型的 Lisp 对象,用于存放指向模块所定义的 C 结构体的指针。
这便于保存模块创建的复杂数据结构,并将其传回给模块的函数使用。
user-ptr 对象还可以关联 终结函数(finalizer)——在对象被垃圾回收(GC)时执行的函数,
可用于释放底层数据结构占用的资源,如内存、打开的文件描述符等。See Conversion Between Lisp and Module Values。
如果参数是 user-ptr 对象,该函数返回 t。
Emacs 使用这个底层原语从指定的 file 加载模块并完成必要的初始化。
该原语会检查模块是否导出了 plugin_is_GPL_compatible 符号,调用模块的 emacs_module_init 函数,
若该函数返回错误或初始化期间用户按下 C-g,则报错。
若初始化成功,module-load 返回 t。
注意:file 必须已经带有正确的扩展名,因为与 load 不同,该函数不会自动尝试已知后缀的文件。
与 load 不同,module-load 不会将模块记入 load-history,不打印任何信息,也不防止递归加载。
因此大多数用户应使用 load、load-file、load-library 或 require,而非直接使用 module-load。
Emacs 中的可加载模块需要在 configure 时使用 --with-modules 选项启用。