在这里,我们将一个 Lisp 应用或库的完整项目文件的集合称为系统,因为项目文件需要当成一个整体。系统定义将指定哪些源文件是用来构建系统的、源文件的的依赖以及以及这些依赖文件编译和加载的顺序。
ASDF
ASDF 是 Common Lisp 的标准构建系统。可以在绝大部分解释器上使用。ASDF 包含了 UIOP, “the Utilities for Implementation- and OS- Portability”。详细知识参考 ASDF 手册 或是 ASDF 教程和最佳实践.
简单示例
加载项目
ASDF最简单的用法就是用(asdf:make :foobar)(或是 load-system)来加载库。比如说,在 foobar 这个库中有个 some-fun 的外部函数,那么调用 some-fun 函数就可以这么写 (foobar:some-fun ...) 或是这样:
(in-package :foobar)(some-fun ...)
当然,也可以用 Quicklisp:
(ql:quickload :foobar)
测试项目
当需要测试一个系统时,可以这样:
(asdf:test-system :foobar)
通常来说如果测试不通过的话是会抛出异常的。
指定项目
在程序中指定系统的正确方法是使用小写字符串,而不是符号,如下:
(asdf:make "foobar")(asdf:test-system "foobar")
简单的项目定义
通常一个项目中会包含个单个的 Lisp 文件如 foobar.lisp,这个文件会依赖一些现有的库,比如通用库 alexandria 和模式匹配库 trivia。为了让项目能用 ASDF 构建,还需要在项目中创建一个 .asd 后缀的文件,如foobar.asd。
(defsystem "foobar":depends-on ("alexandria" "trivia"):components ((:file "foobar")))
注意,上面中的 foobar.lisp 文件类型默认是 lisp,文件的内容大致如下:
(defpackage :foobar(:use :common-lisp :alexandria :trivia)(:export#:some-function#:another-function#:call-with-foobar#:with-foobar))(in-package :foobar)(defun some-function (...)...)...
与其使用多个完整的包,有时只需要导入其中的一部分:
(defpackage :foobar(:use #:common-lisp)(:import-from #:alexandria#:some-function#:another-function))(:import-from #:trivia#:some-function#:another-function))...)
自定义的项目
假设项目是在 ~/common-lisp/、~/quicklisp/local-projects/ 或者是已经在 ASDF 中配置了的路径,就可以直接使用 (asdf:make "foobar") 将项目加载进来。如果已经在创建文件之前启动了 Lisp,就需要重新加载下 ASDF 的配置了:(asdf:clear-configuration)
简单的测试定义
即便是最简单的项目,也需要一些测试单元,因为项目的修改是不可避免的,同时有希望这些修改不会破坏现有的代码。测试同时也是记录预期行为的好方法。
创建测试单元最简单的方法就是创建一个 foobar-tests.lisp 文件,然后在修改下 foobar.asd 文件:
(defsystem "foobar":depends-on ("alexandria" "trivia"):components ((:file "foobar")):in-order-to ((test-op (test-op "foobar/tests"))))(defsystem "foobar/tests":depends-on ("foobar" "fiveam"):components ((:file "foobar-tests")):perform (test-op (o c) (symbol-call :fiveam '#:run! :foobar)))
在第一个 defsystem 中,:in-order-to 从句中标明了可以使用 (asdf:test-system :foobar),这个将链接到 foobar/tests。第二个 defsystem 中的 :perform 是执行自己的测试语句。
在测试单元中,fiveam 这个词比较通用,perform 方法中的内容是运行 :foobar 的测试单元的。当然,具体还是要视情况而定。
创建项目框架
可以使用 cl-project 来创建一个项目框架。这个库会生成一个默认的 ASDF 的定义,一个测试单元等。
通过 quicklisp 安装:
(ql:quickload :cl-project)
创建一个项目:
(cl-project:make-project #p"lib/cl-sample/":author "Eitaro Fukamachi":email "e.arrows@gmail.com":license "LLGPL":depends-on '(:clack :cl-annot));-> writing /Users/fukamachi/Programs/lib/cl-sample/.gitignore; writing /Users/fukamachi/Programs/lib/cl-sample/README.markdown; writing /Users/fukamachi/Programs/lib/cl-sample/cl-sample-test.asd; writing /Users/fukamachi/Programs/lib/cl-sample/cl-sample.asd; writing /Users/fukamachi/Programs/lib/cl-sample/src/hogehoge.lisp; writing /Users/fukamachi/Programs/lib/cl-sample/t/hogehoge.lisp;=> T
