使用 ASDF 的 :around-compile For Individual Files

dav*_*ugh 3 common-lisp asdf compiler-optimization

包含 coredump 响应的SO 帖子展示了如何将编译器策略应用于 ASDF 系统的组件文件:

(defsystem simple-system
  :serial t
  :around-compile (lambda (next)
                    (proclaim '(optimize (debug 3) 
                                         (safety 3)
                                         (debug 3)
                                         (speed 0)))
                    (funcall next))
  :components ((:module "src"
                        :components
                        (...))))
Run Code Online (Sandbox Code Playgroud)

它还提到您可以“隐藏”单个文件,但这将如何工作。这让我感到困惑,因为next在 lambda 表达式中绑定到一个闭包。由于我只需要对几个组件文件应用优化,你如何将这些文件名赋予:around-compile?

cor*_*ump 5

你可以加 :around-compile为系统、模块或文件添加。

更准确地说,如果您有这样的:file组件:

(:file "a")
Run Code Online (Sandbox Code Playgroud)

然后你可以添加:

(:file "a" :around-compile ...)
Run Code Online (Sandbox Code Playgroud)

如果您只想对给定的一组文件应用优化,请将它们分组到一个模块中。您甚至可以将模块的 pathanme 设置为,""以便其文件在同一个目录中是同级组件:

(:module #:MY-OPTIMIZED-FILES
         :depends-on (...)
         ;; SAME DIRECTORY
         :pathname ""
         :serial t
         :around-compile "my-meta-lib:around-compile"
         :components ((:file "a")
                      (:file "b")
                      (:file "c")
                      (:file "d")))
Run Code Online (Sandbox Code Playgroud)

如果未加载定义它的系统,则不能引用符号,并且在 ASDF 系统的情况下,如果不先阅读定义系统的表单,则无法声明依赖项。所以你需要使用字符串来引用另一个包中的符号。

当系统被处理时,字符串必须引用一个现有的符号,所以你需要有一个不同的.asd文件,例如simple-system.meta.asd,它定义了系统"simple-system.meta"。您添加一个依赖项:defsystem-depends-on以确保在处理之前加载系统simple-system

例如,该系统可以是:

(defsystem simple-system.meta
  :depends-on ("trivial-cltl2")
  :components ((:file "meta")))
Run Code Online (Sandbox Code Playgroud)

我使用的原因trivial-cltl2是能够内省全局环境中的声明,并希望限制以下影响proclaim

(defun my-meta-lib:around-compile (next)
  (let ((opt (trivial-cltl2:declaration-information 'optimize)))
    (proclaim '(optimize (debug 3) 
                         (safety 3)
                         (debug 3)
                         (speed 0)))
    (unwind-protect (funcall next)
      (proclaim (list* 'optimize opt)))))
Run Code Online (Sandbox Code Playgroud)

据我所知,proclaim修改全局环境可能会影响其他文件的编译,这就是为什么我更喜欢在编译完成后恢复环境。

SBCL 有一个为此用例制作的实验:policy选项with-compilation-unit,在宏的动态范围内修改策略:

(flet ((debug () (assoc 'debug (sb-cltl2:declaration-information 'optimize))))
  (list (debug)
        (with-compilation-unit (:policy '(optimize (debug 3)))
          (debug))
        (debug)))

 ; => ((DEBUG 1) (DEBUG 3) (DEBUG 1))
Run Code Online (Sandbox Code Playgroud)

  • 是的,因为我认为声明设置了全局编译策略,一旦设置,它就会一直被设置;这就是为什么我尝试使用“my-meta-lib:around-compile”实现一种更可组合的方法,它获取当前声明进行优化,调用声明,然后在展开时恢复以前的声明。我今天进行了编辑以修复我最初遇到的符号与字符串问题,它似乎有效,该策略仅适用于指定的文件 (2认同)
  • 我也想过 (locally (declare (optimize ...)) (funcall next)) 但 hyperspec 不清楚这是否应该在动态范围内工作,我会尝试找到有关该问题的更多信息 (2认同)
  • SBCL 中WITH-COMPILATION-UNIT 的文档字符串表示它有一个`:POLICY` 选项。这是一个依赖于实现的选项,但这是使用 SBCL 执行此操作的正确方法。 (2认同)
  • 请注意,所需的 SBCL 模块名称似乎是“sb-cltl2”。 (2认同)