在cl-mysql的代码中,“#+”是什么意思?

7

最近我尝试阅读有关cl-mysql的代码,但被#+卡住了。

尝试在谷歌上搜索,但没有结果,所以来到这里寻求帮助。

(defun make-lock (name)
  #+sb-thread (sb-thread:make-mutex :name name)
  #+ecl (mp:make-lock :name name)
  #+armedbear (ext:make-thread-lock)
  #+ (and clisp mt) (mt:make-mutex :name name)
  #+allegro (mp:make-process-lock :name name))

看起来这是为不同的后端lisp编译器而写的。但仍然不知道为什么要写这样的东西。 有人能帮我搞清楚吗,谢谢。


1
我将此标记为重复问题,因为其他问题已经回答了这个问题,但我会点赞它,因为这是一个很好的例子,展示了这个构造如何使用,正如你所指出的,要知道它被称为什么(在这一点上,通常就不需要再搜索了)确实很困难。 - Joshua Taylor
2个回答

11

#+是一个读取宏,用于检查关键字是否在特殊变量*FEATURES*中。如果不在其中,则以下表单将被跳过(由读取器;编译器永远不会看到它)。还有#-执行相反的操作。

有些东西不是Common Lisp标准的一部分,但它们非常重要,以至于所有(或大多数)实现都为它们提供了非标准扩展。当您想在需要在多个实现上工作的代码中使用它们时,您必须使用读取时条件来为当前实现提供正确的代码。互斥体(以及线程一般)就是其中之一。

当然也可能有第三方库提供的功能。 *FEATURES*的内容类似于:

(:SWANK :QUICKLISP :SB-BSD-SOCKETS-ADDRINFO :ASDF-PACKAGE-SYSTEM :ASDF3.1
 :ASDF3 :ASDF2 :ASDF :OS-UNIX :NON-BASE-CHARS-EXIST-P :ASDF-UNICODE :64-BIT
 :64-BIT-REGISTERS :ALIEN-CALLBACKS :ANSI-CL :ASH-RIGHT-VOPS
 :C-STACK-IS-CONTROL-STACK :COMMON-LISP :COMPARE-AND-SWAP-VOPS
 :COMPLEX-FLOAT-VOPS :CYCLE-COUNTER :ELF :FLOAT-EQL-VOPS
 :FP-AND-PC-STANDARD-SAVE :GENCGC :IEEE-FLOATING-POINT :INLINE-CONSTANTS
 :INTEGER-EQL-VOP :INTERLEAVED-RAW-SLOTS :LARGEFILE :LINKAGE-TABLE :LINUX
 :LITTLE-ENDIAN :MEMORY-BARRIER-VOPS :MULTIPLY-HIGH-VOPS :OS-PROVIDES-DLADDR
 :OS-PROVIDES-DLOPEN :OS-PROVIDES-GETPROTOBY-R :OS-PROVIDES-POLL
 :OS-PROVIDES-PUTWC :OS-PROVIDES-SUSECONDS-T :PACKAGE-LOCAL-NICKNAMES
 :PRECISE-ARG-COUNT-ERROR :RAW-INSTANCE-INIT-VOPS :SB-DOC :SB-EVAL :SB-FUTEX
 :SB-LDB :SB-PACKAGE-LOCKS :SB-SIMD-PACK :SB-SOURCE-LOCATIONS :SB-TEST
 :SB-THREAD :SB-UNICODE :SBCL :STACK-ALLOCATABLE-CLOSURES
 :STACK-ALLOCATABLE-FIXED-OBJECTS :STACK-ALLOCATABLE-LISTS
 :STACK-ALLOCATABLE-VECTORS :STACK-GROWS-DOWNWARD-NOT-UPWARD :SYMBOL-INFO-VOPS
 :UNIX :UNWIND-TO-FRAME-AND-CALL-VOP :X86-64)

如果你想编写依赖于Quicklisp的代码,可以使用#+quicklisp。如果你想编写仅在Quicklisp不可用时运行的代码,则可以使用#-quicklisp
你还可以使用功能的布尔表达式。例如,
#+(or sbcl ecl) (format t "Foo!")

在SBCL或ECL上,将会打印Foo!
#+(and sbcl quicklisp) (format t "Bar!")

只有在安装了Quicklisp的SBCL上,才会打印出Bar!

感谢您的评论,非常感谢。 - c0rehe110

5

我们可以想象写出以下代码:

(defun make-lock (name)
  (cond ((member :sb-thread *features)
         (sb-thread:make-mutex :name name))
        ((member :ecl *features*)
         (mp:make-lock :name name))
     ...))

但通常情况下这并不起作用,因为当它们的包不存在时我们无法读取符号,并且有些包是特定于实现/库/应用程序的。包在读取时不会以懒惰/自动方式创建。

在Common Lisp中,读取一个不存在的包的符号会导致错误:

CL-USER 1 > (read-from-string "foo:bar")

Error: Reader cannot find package FOO.
  1 (continue) Create the FOO package.
  2 Use another package instead of FOO.
  3 Try finding package FOO again.
  4 (abort) Return to level 0.
  5 Return to top loop level 0.

在你的例子中,sb-thread:make-mutex 是一个在SBCL中有意义但在Allegro CL中没有意义的符号。此外,在Allegro CL中不存在SB-THREAD包。因此,需要保护Allegro CL免受读取该符号的影响。在这种情况下,只有当cl:*features*列表中存在sb-thread特性时,才会读取符号sb-thread:make-mutex。这很可能只适用于SBCL或声称具有可用sb-threads的Lisp。
这里的特性表达式防止Lisp尝试读取具有未知包的符号——包是未知的,因为相应的软件未加载或不可用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接