You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Common Lisp编译生成的fasl能否留存编译时信息并在运行时调用?

如何让Common Lisp的FASL文件留存编译时信息

你的问题核心是:编译阶段通过eval-when (:compile-toplevel)赋值的变量值,并没有被写入FASL文件,导致新会话加载时变量回到初始的nil状态。要解决这个问题,需要把编译时计算的值嵌入到生成的FASL文件中,让加载时能直接读取固化后的信息。

原代码问题分析

原代码中eval-when (:compile-toplevel)的赋值操作仅在编译当前会话中生效,这个赋值过程不会被记录到FASL文件里。FASL只保存了defvar *compilation-time* nil的变量定义,所以新会话加载时,变量初始值仍是nil。

解决方案:固化编译时信息到FASL

方法1:使用defconstant直接固化值

defconstant的初始表达式会在编译阶段求值,求值结果会被直接写入FASL文件,加载时无需重新计算:

(in-package :cl-user)

(defconstant *compilation-time*
  (multiple-value-bind (s m h)
      (decode-universal-time (get-universal-time))
    (format nil "~D:~D:~D" h m s))
  :documentation "编译该文件的时间")

(defconstant *compilation-path*
  *compile-file-pathname*
  :documentation "编译时的源文件路径")

(format t "Built at: ~A~%" *compilation-time*)
(format t "Built from: ~A~%" *compilation-path*)

方法2:动态生成加载时赋值代码

如果不需要用常量(允许后续修改变量值),可以在编译阶段计算值,然后生成加载时执行的赋值语句,嵌入到FASL中:

(in-package :cl-user)

(defvar *compilation-time* nil)
(defvar *compilation-path* nil)

(eval-when (:compile-toplevel)
  ;; 在编译阶段计算时间和路径
  (let ((current-time (multiple-value-bind (s m h)
                          (decode-universal-time (get-universal-time))
                        (format nil "~D:~D:~D" h m s)))
        (source-path *compile-file-pathname*))
    ;; 生成加载时执行的赋值代码,把编译时的值固化进去
    (eval `(eval-when (:load-toplevel :execute)
             (setf *compilation-time* ,current-time)
             (setf *compilation-path* ,source-path)))))

(format t "Built at: ~A~%" *compilation-time*)
(format t "Built from: ~A~%" *compilation-path*)

测试效果

编译后加载FASL文件,就能看到正确的编译时间和路径:

# sbcl --noinform --no-userinit
* (load "foo.fasl")
Built at: 17:33:20
Built from: #P"/tmp/common-lisp/foo.lisp"
T
* *compilation-time*
"17:33:20"

内容的提问来源于stack exchange,提问作者xiepan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 19:27:49