编写库
生态系统概述
在 Common Lisp 中,构建系统和包管理器是两个独立的部分。
- ASDF
- ASDF 是构建系统。它让你可以定义项目,称为“系统”,以及它们的元数据、依赖项、源代码文件和文件加载顺序。
- Quicklisp
- Quicklisp 是包管理器。它使用 ASDF 来提取包的依赖项并从中心存储库下载它们。与大多数包管理器不同,Quicklisp 不是命令行应用程序:你可以像其他任何 Lisp 工具一样在 REPL 中运行它,所以你可以非常轻松地上手。
定义系统
一个典型的系统定义如下所示(来自 此 项目)
(defsystem common-doc
:author "Fernando Borretti <eudoxiahp@gmail.com>"
:maintainer "Fernando Borretti <eudoxiahp@gmail.com>"
:license "MIT"
:version "0.2"
:homepage "https://github.com/CommonDoc/common-doc"
:bug-tracker "https://github.com/CommonDoc/common-doc/issues"
:source-control (:git "git@github.com:CommonDoc/common-doc.git")
:description "A framework for representing and manipulating documents as CLOS objects."
:depends-on (:trivial-types
:local-time
:quri
:anaphora
:alexandria
:closer-mop)
:components ((:module "src"
:serial t
:components
((:file "packages")
(:file "define")
(:file "error")
(:file "file")
(:file "classes")
(:file "metadata")
(:file "constructors")
(:file "macros")
(:file "format")
(:file "util")
(:module "operations"
:serial t
:components
((:file "traverse")
(:file "figures")
(:file "tables")
(:file "links")
(:file "text")
(:file "unique-ref")
(:file "toc")
(:file "equality")))
(:file "print"))))
:long-description
#.(uiop:read-file-string
(uiop:subpathname *load-pathname* "README.md"))
:in-order-to ((test-op (test-op common-doc-test))))
分解一下,第一行定义系统名称,common-doc
。
接下来,我们有元数据
:author "Fernando Borretti <eudoxiahp@gmail.com>"
:maintainer "Fernando Borretti <eudoxiahp@gmail.com>"
:license "MIT"
:version "0.2"
:homepage "https://github.com/CommonDoc/common-doc"
:bug-tracker "https://github.com/CommonDoc/common-doc/issues"
:source-control (:git "git@github.com:CommonDoc/common-doc.git")
:description "A framework for representing and manipulating documents as CLOS objects."
ASDF 允许我们提供作者的联系信息(名称和电子邮件地址)、许可信息、版本字符串、一些有用的链接以及一行描述。
然后,我们有依赖项列表
:depends-on (:trivial-types
:local-time
:quri
:anaphora
:alexandria
:closer-mop)
这只是一个系统所依赖的系统列表。此处可以指定版本,但通常在外部进行版本管理,请见下面。
紧随其后的是组件,基本上是源代码树的描述。模块是目录,文件是 Lisp 文件。
:components ((:module "src"
:serial t
:components
((:file "packages")
(:file "define")
(:file "error")
(:file "file")
(:file "classes")
(:file "metadata")
(:file "constructors")
(:file "macros")
(:file "format")
(:file "util")
(:module "operations"
:serial t
:components
((:file "traverse")
(:file "figures")
(:file "tables")
(:file "links")
(:file "text")
(:file "unique-ref")
(:file "toc")
(:file "equality")))
(:file "print"))))
:serial t
选项基本上表示“此目录中的文件应按此处显示的顺序加载。ASDF 还允许我们更复杂,并手动指定哪些文件依赖于哪些文件,并且只要让 ASDF 确定加载它们的总顺序即可。但对于大多数情况,只需使用 :serial t
即可足够。
然后,我们使用 :long-description
选项和读取时执行将 README.md
文件嵌入到系统定义中
:long-description
#.(uiop:read-file-string
(uiop:subpathname *load-pathname* "README.md"))
此选项由诸如 [Quickdocs][qd] 之类的工具用于显示关于系统的信息。
最后,我们告诉 ASDF 关于关联的测试系统,这是加载测试框架并运行独立测试的系统。我们将在单元测试指南中介绍它。
:in-order-to ((test-op (test-op common-doc-test)))
配置 ASDF
在加载系统之前,您必须告诉 ASDF 在何处找到它们。这在 ~/.config/common-lisp/source-registry.conf
文件中指定。
例如,以下配置
(:source-registry
(:tree (:home "code"))
:inherit-configuration)
告诉 ASDF 在 ~/code/
目录中递归搜索以查找您的系统,并从 Quicklisp 继承配置以便您可以加载 Quicklisp 的系统。
加载
当您配置 ASDF 并创建了您的系统后,您可以使用 Quicklisp 或 ASDF 加载它
CL-USER> (asdf:load-system :my-system)
CL-USER> (ql:quickload :my-system)