Mario S. Mommer <firstname.lastname@example.org>
Last modified: .
The aim of this document is to give a brief introduction to the use of
ASDF, Another System Definition Facility. It is not about the
arcane tricks and tips, and is not about the design of
itself nor about system definition tools in general.
A system definition file is nothing else than a description of
dependencies between files of source code in such a way that they can
be compiled and loaded in the right order. A file
A.lisp depends on a
B.lisp if the latter contains definitions and/or code that is
Solving this problem is in the vast majority of cases fairly trivial,
so hacking up some minimal script will usually work. Learning the
right tool, however, will save you a lot of time down the road. In
this minitutorial we will concentrate on the simple cases and on the
general usage of a fairly well known tool,
ASDF. We leave the more
advanced features of this tool to the
When you download the source code of some software from the Internet, or get it from some other source, you usually do not get an amorphous bunch of files, but instead get a system of components that depend on each other in some particular way. The consequence of this is that, if you want to build the software (be it a library, or be it an application), you will probably have to build these components, and the components of these components in order, perhaps giving some special treatment to some of them. You would, of course, be very grateful if the developer had prepared everything, and you could trigger the build process by a single command.
If you are a developer working in a project with a few components, you will probably want some mechanism that keeps track of the dependencies between these components, so that if you change one component, triggering a rebuild only recompiles and reloads the components which are affected.
Finally, you probably want a consistent way of dealing with the dependencies between components and of building and loading software systems, simply because it saves everyone time when installing software and using software.
ASDF is, roughly speaking, an extensible facility for defining the
dependencies between software components, and specifying eventual
details of the build process. It is also in fairly wide use, so that
you can assume that your system definition will be understood by many
The same can be said about
mk:defsystem, which has fans as well
as detractors. We will only concentrate here on
ASDF, since we
have to start somewhere. In any case, the actual differences between
these two only become apparent for the power user.
This work is licensed under a Creative Commons Attribution 2.5 License.
ASDF system definition is stored in a file with the extension
.asd. To make the discussion clearer, we are going to pretend that we
want to write the system definition facility for our software project,
The system definition file should be called
cow.asd, and, at least in
the usual scenarios, should reside in the same directory as your
source code. If you use emacs, you might want to put the following as
the first line in
;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10 -*-
This makes sure that the proper syntax support is turned on, which is
necessary because by default emacs knows nothing about
cow.asd should start with the following code
(preceded or followed perhaps by comments; goes almost without saying)
(defpackage #:cow-asd (:use :cl :asdf)) (in-package :cow-asd)
The next thing is to write a
defsystem form, together with some
(optional) extra information.
(defsystem cow :name "cow" :version "0.0.0" :maintainer "T. God" :author "Desmon Table" :licence "BSD sans advertising clause (see file COPYING for details)" :description "Cow" :long-description "Lisp implementation of our favorite ruminant"
As you might have guessed, only the first line is mandatory.
In the simplest case you have a directory with a few files. And the absolutely simplest case is when the dependency of your files is linear. That is, you can make a list of the files such that the first one should be loaded first, the second second, etc.
In such a case, the
defsystem form can look like this.
(defsystem cow ;;; (Optional items omitted) :serial t ;; the dependencies are linear. :components ((:file "defpackage") (:file "legs") (:file "tail") (:file "head")))
Suppose that we have the same files as before, but would like to
specify the dependencies more accurately. There is a file called
defpackage.lisp, from which everything else depends. And we have that,
for some mysterious reason,
tail.lisp depends on
defsystem form for this project could look as follows.
(defsystem cow ;;; (Optional items omitted) :components ((:file "tail" :depends-on ("package" "legs")) (:file "legs" :depends-on ("package")) (:file "head" :depends-on ("package")) (:file "package")))
In this case you would keep the file
cow.asd in the same directory as
the source files. If you want to try out our nice
cow system, you can
jump directly to the pertinent section.
Suppose that we have the following, more involved structure. We have a
legs.lisp. But we also have a subsystem called
respiratory, which consists of a few more files, and lives in its own
breathing (this is a subdirectory of the directory
cow.asd lives). Similarly, we have another subsystem called
defsystem form could look more or less like this.
(defsystem cow :components ((:file "head" :depends-on ("package")) (:file "tail" :depends-on ("package" circulation)) (:file "package") (:module circulation :components ((:file "water" :depends-on "package") (:file "assorted-solids" :depends-on "package") (:file "package"))) (:module respiratory :pathname "breathing" :components (...))))
Note that the files in the module
circulation all live in the
circulation. Thus the file
package.lisp in the
circulation is a different one than that a level higher.
A module can have as components both files and other modules, which in
turn can have files and modules as components. It is important to note
that dependencies can only be defined inside a given set of
components. So, the file
tail.lisp cannot depend on the
assorted-solids, which is a component of a submodule.
A system that depends on other systems will look exactly like a
regular one, except for an additional
:depends-on option. It looks
(defsystem cow ;;; ... :components (...) :depends-on ("other-system"))
System definition files live in the directory where the corresponding
piece of software lives. However, you do not need to have that
directory as your working directory to be able to build and load said
software. You only need to put a symbolic link to the system
definition file in a directory where
The usual setup is as follows. To begin with, you need to have
loaded. In some implementations
ASDF is already loadad. In others, it
is just a matter of writing
(require 'asdf)whereas in others you might need to install it yourself first. You can get it, in a single file, from here, and put it somewhere reasonable. For instance, if your login name was
foo, in the directory
/home/foo/lisp/utils/. You may also want to compile that file.
Now, somewhere in the init file of your Common Lisp implementation
(for CMUCL it would be
.cmucl-init.lisp in your home directory) a variation
of the following passage should appear.
(load "/home/foo/lisp/utils/asdf") (setf asdf:*central-registry* ;; Default directories, usually just the ``current directory'' '(*default-pathname-defaults* ;; Additional places where ASDF can find ;; system definition files #p"/home/foo/lisp/systems/" #p"/usr/share/common-lisp/systems/"))
The command to build and load system cow is
(asdf:operate 'asdf:load-op 'cow)
If the file
cow.asd happens to be in the current working
directory, the build and load process will start there. If not, ASDF
will search through the directories in the central registry, and look
for a system definition file named
cow.asd, or for a
symbolic link to one. If it finds the latter, it will follow the link
to the original file, and run the build process in the corresponding
directory. If it finds the file, it will run the build process in the
directory where it finds it.
So, if you make a symbolic link in
cow system definition file, by executing (for example)
$ cd <where-your-system-defs-are> $ ln -s /home/foo/code/cow/cow.asd
Then you can build and load the cow software without having to be in the directory where this software lives simply by issuing the command
(asdf:operate 'asdf:load-op 'cow)
1. In lisp, things can get a little more complicated. We limit ourselves here to the most common cases, and for them this definition is good enough.
2. D. Barlow et al., ``asdf Manual''