0

这是一个奇怪的情况。我有这个代码:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (ql:quickload "cffi-grovel")
  (setf cffi-grovel::*cc* "mpicc")) ; <--- this is the line it complains about.

我相信在设置变量cffi-grovel之前必须加载包。cffi-grovel::*cc*当这个表单从 SLIME 执行时它可以工作,但是当它直接由 SBCL 加载时它不起作用,这是输出:

$ sbcl --noinfo
* (ql:quickload "cl-mpi")

debugger invoked on a LOAD-SYSTEM-DEFINITION-ERROR in thread
#<THREAD "main thread" RUNNING {10029C0E43}>:
  Error while trying to load definition for system cl-mpi from pathname
  /home/wvxvw/quicklisp/local-projects/cl-mpi/cl-mpi.asd:
     READ error during COMPILE-FILE:

       Package CFFI-GROVEL does not exist.

         Line: 6, Column: 25, File-Position: 264

< restarts ... >

* (ql:quickload "cffi-grovel")
To load "cffi-grovel":
  Load 1 ASDF system:
    cffi-grovel
; Loading "cffi-grovel"
..
("cffi-grovel")
* (ql:quickload "cl-mpi")
To load "cffi-grovel":
  Load 1 ASDF system:
    cffi-grovel
; Loading "cffi-grovel"

To load "cl-mpi":
  Load 1 ASDF system:
    cl-mpi
; Loading "cl-mpi"
; mpicc -m64 ...
; ...
.
("cl-mpi")

为什么第一次失败?

PS。我也尝试过#.cffi-grovel::*cc*- 结果相同。

4

3 回答 3

6

它失败了,因为 Lisp 在执行之前读取了每个表单。当它读取它时,包 cffi-grovel 确实还不存在,因为 cffi-grovel 是在执行时加载的(无论它对用 eval-when 包装的表单意味着什么)。

尝试将 eval-when 表单拆分为两个 eval-when:ql:quickload 和 setf。或者这样写:

(setf (symbol-value (find-symbol "*CC*" "CFFI-GROVEL"))
      "mpicc")
于 2013-11-10T02:29:26.527 回答
0

好的,终于想通了,我可以这样做:

(setf #.(intern "cffi-grovel::*cc*") "mpicc")

但我不确定这在多大程度上是故障安全的。

于 2013-11-10T00:39:02.083 回答
0

monoid 给出了一个很好的答案。这是一个略短的形式。

当包实际存在时,在运行时查找符号。注意使用SET, not SETFhere:

(set (find-symbol "*CC*" "CFFI-GROVEL") "mpicc")

为了使其更健壮,需要检查是否FIND-SYMBOL确实找到了符号。以下函数还为您提供有意义的错误消息并重新启动:

(defun set-runtime-symbol (name package value)
  (assert (find-package package) (package))
  (assert (find-symbol name package) (name))
  (set (find-symbol name package) value))

或者使用两个 EVAL-WHEN 语句,而不是一个。

于 2013-11-10T06:42:09.630 回答