这是一个奇怪的情况。我有这段代码:
(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*
- 结果相同。
答案 0 :(得分:6)
它失败,因为Lisp在执行之前读取每个表单。当它读取它时,包cffi-grovel确实还不存在,因为cffi-grovel在执行时被加载(无论它对于包含eval-when的表单意味着什么)。
尝试将eval-when表单拆分为两个eval-whens:ql:quickload和setf。或写下这样的东西:
(setf (symbol-value (find-symbol "*CC*" "CFFI-GROVEL"))
"mpicc")
答案 1 :(得分:0)
好的,终于想通了我可以这样做:
(setf #.(intern "cffi-grovel::*cc*") "mpicc")
但我不确定这是多少故障安全。
答案 2 :(得分:0)
monoid给出了一个很好的答案。这是一个略短的表格。
在程序包实际存在时,在运行时查找符号。请注意SET
的使用,而不是SETF
:
(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语句,而不是一个。