Starting with release 3.1.2,
ASDF supports a one-package-per-file style of programming,
in which each file is its own system,
and dependencies are deduced from the
or its variant,
In this style of system definition, package names map to systems with
the same name (in lower case letters),
and if a system is defined with
then system names that start with that name
(using the slash
refer to files under the filesystem hierarchy where the system is defined.
For instance, if system
my-lib is defined in
/foo/bar/my-lib/my-lib.asd, then system
will be found in file /foo/bar/my-lib/src/utility.lisp.
One package per file style was made popular by
and at the cost of stricter package discipline,
may yield more maintainable code.
This style is used in ASDF itself (starting with ASDF 3), by
and a few other libraries.
To use this style, choose a toplevel system name, e.g.
and create a file my-lib.asd.
:class :package-inferred-system option in its
;; This example is based on lil.asd of LISP-INTERFACE-LIBRARY. #-asdf3.1 (error "MY-LIB requires ASDF 3.1 or later.") (defsystem "my-lib" :class :package-inferred-system :depends-on ("my-lib/interface/all" "my-lib/src/all" "my-lib/extras/all") :in-order-to ((test-op (load-op "my-lib/test/all"))) :perform (test-op (o c) (symbol-call :my-lib/test/all :test-suite))) (defsystem "my-lib/test" :depends-on ("my-lib/test/all")) (register-system-packages "my-lib/interface/all" '(:my-lib-interface)) (register-system-packages "my-lib/src/all" '(:my-lib-implementation)) (register-system-packages "my-lib/test/all" '(:my-lib-test)) (register-system-packages "closer-mop" '(:c2mop :closer-common-lisp :c2cl :closer-common-lisp-user :c2cl-user))
In the code above, the first form checks that we are using ASDF 3.1 or
later, which provides
package-inferred-system. This is probably
no longer necessary, since none of the major lisp implementations
provides an older version of ASDF.
register-system-packages must be called to register
packages used or provided by your system
when the name of the system/file that provides the package
is not the same as the package name (converted to lower case).
Each file under the
my-lib hierarchy will start with a
uiop:define-package is supported as well as
ASDF will compute dependencies from the
:mix, and other importation clauses of this package definition. Take the file
interface/order.lisp as an example:
(uiop:define-package :my-lib/interface/order (:use :closer-common-lisp :my-lib/interface/definition :my-lib/interface/base) (:mix :fare-utils :uiop :alexandria) (:export ...))
ASDF can tell that this file/system depends on system
closer-mop (registered above),
How can ASDF find the file interface/order.lisp from the
my-lib, however? In the example above,
interface/all.lisp (and other all.lisp) reexport
all the symbols exported from the packages at the same or lower levels
of the hierarchy. This can be easily done with
uiop:define-package, which has many options that prove useful in this
context. For example:
(uiop:define-package :my-lib/interface/all (:nicknames :my-lib-interface) (:use :closer-common-lisp) (:mix :fare-utils :uiop :alexandria) (:use-reexport :my-lib/interface/definition :my-lib/interface/base :my-lib/interface/order :my-lib/interface/monad/continuation))
Thus the top level system need only depend on the
because ASDF detects
interface/order.lisp and all other dependencies from
:use-reexport clauses, which effectively
allow for “inheritance” of symbols being exported.
ASDF also detects dependencies from
You may thus import a well-defined set of symbols from an existing
package, and ASDF will know to load the system that provides that
package. In the following example, ASDF will infer that the current
system depends on
foo/baz from the first
If you prefer to use any such symbol fully qualified by a package prefix,
you may declare a dependency on such a package and its corresponding system
:import-from clause with an empty list of symbols. For
example, if we preferred to use the name ‘foo/quux:bletch‘, the second,
:import-from form would cause ASDF to load
(defpackage :foo/bar (:use :cl) (:import-from :foo/baz #:sym1 #:sym2) (:import-from :foo/quux) (:export ...))
Note that starting with ASDF 18.104.22.168 only, ASDF will look for source files under
component-pathname (specified via the
whereas earlier versions ignore this option and use the
where the .asd file resides.