Skip to content

Lisp - 定义系统

在现代 Common Lisp 中,一个 **系统(system)**是构成库或应用程序的源文件集合。ASDF (Another System Definition Facility) 是定义这些系统、管理其组件和处理依赖关系的事实标准工具。可以把 ASDF 文件(.asd)看作是 Rust 中的 Cargo.toml 或 Node.js 中的 package.json 的等价物。

你通过创建一个名为 your-system-name.asd 的文件来定义一个系统。这个文件包含一个 Lisp 形式,它使用 asdf:defsystem 来声明元数据和组件。

;;;; my-library.asd
(asdf:defsystem #:my-library
:description "A brief description of my new library."
:author "Your Name <you@example.com>"
:license "MIT"
:version "0.1.0"
:serial t ; 确保组件按列出的顺序加载。
;; 声明该库依赖的其他系统。
;; 如果它们不可用,ASDF 会要求 Quicklisp 获取它们。
:depends-on (#:alexandria
#:drakma)
;; 定义构成系统的文件和模块。
:components ((:file "packages") ; 通常是第一个文件,定义包。
(:file "utils")
(:file "main")))
  • :description, :author, :license, :version:项目的标准元数据。
  • :depends-on:你的项目所需的其他 ASDF 系统列表。这是依赖管理的基础。
  • :components:系统组成部分的列表。最常见的类型是 :file(用于单个 .lisp 文件,不带扩展名)和 :module(用于包含更多组件的子目录)。
  • :serial t:一个便捷选项,告诉 ASDF 按照它们在 :components 列表中出现的精确顺序编译和加载组件。这对于更简单的系统来说非常常见。

一个典型的 Common Lisp 项目遵循标准的目录布局:

my-library/
├── my-library.asd ; 系统定义文件
├── README.md
├── LICENSE
├── packages.lisp ; 定义系统的包
├── main.lisp ; 主源代码
└── utils.lisp ; 工具函数

Quicklisp 是 Common Lisp 的标准库管理器。它与 ASDF 协同工作。虽然你可以直接使用 ASDF,但现代的工作流程是使用 Quicklisp,它反过来会使用 ASDF 来构建和加载你的系统及其依赖项。

要加载你正在开发的本地项目,你必须首先确保 Quicklisp 知道在哪里找到它。最简单的方法是将你的项目文件夹放入 ~/quicklisp/local-projects/。一旦项目在那里,你就可以从 REPL 中加载它:

;; 将你的系统(及其依赖项)加载到你的 Lisp 镜像中。
(ql:quickload :my-library)

Quicklisp 将找到 my-library.asd,解析它,如果需要,下载 :depends-on 中列出的所有依赖项,然后要求 ASDF 按正确顺序编译并加载所有组件文件。

  • 标准化:ASDF 为 Common Lisp 提供了通用的“项目文件”格式,使得其他人可以轻松使用你的代码。
  • 依赖管理:与 Quicklisp 无缝集成,实现所需库的自动获取和加载。
  • 自动编译:ASDF 跟踪文件更改,仅在必要时重新编译文件,从而加速你的开发工作流程。
  • 可移植性:ASDF 定义的系统可以被任何开发者在任何主流 Common Lisp 实现(如 SBCL、CCL 等)上加载和使用。

ASDF 还可以配置为运行你的项目的测试套件。这通常涉及向你的系统定义添加 :test-op 并使用 FiveAM 或 Parachute 等测试框架。

;; 配置完成后,你可以像这样运行测试:
(asdf:test-system :my-library)