在配置文件中为(尚未加载的)包定义设置



在Common Lisp(+今天的公共库)中是否有任何标准的方法来将尚未加载的库/系统(来自公共资源并且不能合理修改)的默认设置放在配置文件中,如.sbclrc?

例如,我想设置

(setf quickproject:*template-directory* "~/projects/template/"
quickproject:*author* "my name <etcetc>")

当Quickproject加载时。(显然,相关的包在那个时候没有定义,这是一个额外的复杂问题,但我可以处理。)

类似于emacs的(with)-eval-after-load

我主要对sbcl和quicklisp/asdf库感兴趣,但优先考虑独立于实现的解决方案。

我试图在现有的库中找到SBCL require和asdf的开箱即用的功能,但没有成功。

我考虑并拒绝了在trace中滥用sbcl的扩展。

到目前为止,我能做的最好的是为asdf:operate定义方法,就像(为了说明,没有真正使用)

(defvar *after-system-hooks* (make-hash-table :test 'equal))
(defmethod asdf:operate :after ((op asdf:load-op) (component asdf:system) &key)
(let* ((name (asdf:component-name component)))
(dolist (hook (gethash name *after-system-hooks*))
(funcall hook))
(setf (gethash name *after-system-hooks*) nil)))
(defun intern-uninterned (code package)
(typecase code
(cons (cons (intern-uninterned (car code) package)
(intern-uninterned (cdr code) package)))
(symbol (if (symbol-package code) code (intern (symbol-name code) package)))
(t code)))
(defmacro with-eval-after-load ((name package) &body body)
`(let ((fn (lambda () (eval (intern-uninterned '(progn ,@body) ',package)))))
(if (member ,name (asdf:already-loaded-systems) :test 'equal)
(funcall fn)
(push fn (gethash ,name *after-system-hooks*)))))

,然后写成

(with-eval-after-load ("quickproject" :quickproject)
(setf
#:*template-directory*  "~/projects/template/"
#:*author*   "My Name <etcetc>"))
然而,这是在标准类上调度的标准组件上的重写方法,因此它似乎不安全,也不适合未来。而且我不知道如何定义新的类来专门化,使其能够与现有的系统和工具一起工作。

(它有eval,但它不打扰我在这里)

你在asdf:operate的轨道上是正确的。但是一般来说,不要专门化asdf:system,而是使用EQL专门化器:

(defmethod asdf:operate :after ((op asdf:load-op) (component (eql (asdf:find-system "quickproject"))) &key)
... )

这个方法只在加载Quickproject后调用。

我也会去掉额外的抽象,只做我想在方法本身做的事情。有uiop:symbol-call调用一个尚未加载的函数。但我不介意使用eval与固定字符串。

要从多个实现中使用此方法(以及类似的自定义表单),只需将其放在shared-init.lisp文件中,然后将该文件加载到每个实现的init文件中。

至于您自己代码的设置和配置的通用库,我以前使用过https://github.com/Shinmera/ubiquitous,它没有任何问题。

最新更新