ASDF is the standard build system for Common Lisp. It is shipped in most Common Lisp implementations. It includes UIOP, “the Utilities for Implementation- and OS- Portability”. You can read its manual and the tutorial and best practices.
Loading a system
The most trivial use of ASDF is by calling
(asdf:make "foobar") (or
to load your library.
Then you can use it.
For instance, if it exports a function
some-fun in its package
then you will be able to call it with
(foobar:some-fun ...) or with:
(in-package :foobar) (some-fun ...)
You can also use Quicklisp:
Also, you can use SLIME to load a system, using the
M-x slime-load-system Emacs command.
The interesting thing about this way of doing it is that SLIME collects all the system warnings and errors in the process,
and puts them in the
*slime-compilation* buffer, from which you can interactively inspect them after the loading finishes.
Testing a system
To run the tests for a system, you may use:
The convention is that an error SHOULD be signalled if tests are unsuccessful.
Designating a system
The proper way to designate a system in a program is with lower-case strings, not symbols, as in:
(asdf:make "foobar") (asdf:test-system "foobar")
How to write a trivial system definition
A trivial system would have a single Lisp file called
foobar.lisp, located at the project’s root.
That file would depend on some existing libraries,
alexandria for general purpose utilities,
trivia for pattern-matching.
To make this system buildable using ASDF,
you create a system definition file called
with the following contents:
(defsystem "foobar" :depends-on ("alexandria" "trivia") :components ((:file "foobar")))
Note how the type
is implicit in the name of the file above.
As for contents of that file, they would look like this:
(defpackage :foobar (:use :common-lisp :alexandria :trivia) (:export #:some-function #:another-function #:call-with-foobar #:with-foobar)) (in-package :foobar) (defun some-function (...) ...) ...
using multiple complete packages, you might want to just import parts of them:
(defpackage :foobar (:use #:common-lisp) (:import-from #:alexandria #:some-function #:another-function)) (:import-from #:trivia #:some-function #:another-function)) ...)
Using the system you defined
Assuming your system is installed under
~/quicklisp/local-projects/ or some other filesystem hierarchy
already configured for ASDF, you can load it with:
If your Lisp was already started when you created that file, you may have to, either:
- load the new .asd file:
(load "path/to/foobar.asd"), or with
C-c C-kin Slime to compile and load the whole file.
(asdf:clear-configuration)to re-process the configuration.
How to write a trivial testing definition
Even the most trivial of systems needs some tests, if only because it will have to be modified eventually, and you want to make sure those modifications don’t break client code. Tests are also a good way to document expected behavior.
The simplest way to write tests is to have a file
and modify the above
foobar.asd as follows:
(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)))
:in-order-to clause in the first system
allows you to use
which will chain into
:perform clause in the second system does the testing itself.
In the test system,
fiveam is the name of a popular test library,
and the content of the
perform method is how to invoke this library
to run the test suite
Obvious YMMV if you use a different library.
Create a project skeleton
cl-project can be used to generate a project skeleton. It will create a default ASDF definition, generate a system for unit testing, etc.
Create a project:
(cl-project:make-project #p"lib/cl-sample/" :author "Eitaro Fukamachi" :email "email@example.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
And you’re done.
Page source: systems.md