Previous: Other code in .asd files, Up: Defining systems with defsystem [Contents][Index]
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 defpackage
form
or its variant, uiop:define-package
.
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 :class package-inferred-system
,
then system names that start with that name
(using the slash /
separator)
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 my-lib/src/utility
will be found in file /foo/bar/my-lib/src/utility.lisp.
One package per file style was made popular by faslpath
and quick-build
,
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 lisp-interface-library
,
and a few other libraries.
To use this style, choose a toplevel system name, e.g. my-lib
,
and create a file my-lib.asd.
Define my-lib
using the :class :package-inferred-system
option in its defsystem
.
For instance:
;; 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.
The function 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
package definition.
The form uiop:define-package
is supported as well as
defpackage
.
ASDF will compute dependencies from the
:use
, :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),
my-lib/interface/definition
, and my-lib/interface/base
.
How can ASDF find the file interface/order.lisp from the
toplevel system 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 my-lib/.../all
systems
because ASDF detects
interface/order.lisp and all other dependencies from all
systems’ :use-reexport
clauses, which effectively
allow for “inheritance” of symbols being exported.
ASDF also detects dependencies from :import-from
clauses.
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 :import-from
.
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
via an :import-from
clause with an empty list of symbols. For
example, if we preferred to use the name ‘foo/quux:bletch‘, the second,
empty, :import-from
form would cause ASDF to load
foo/quux
.
(defpackage :foo/bar (:use :cl) (:import-from :foo/baz #:sym1 #:sym2) (:import-from :foo/quux) (:export ...))
Note that starting with ASDF 3.1.5.6 only, ASDF will look for source files under
the component-pathname
(specified via the :pathname
option),
whereas earlier versions ignore this option and use the system-source-directory
where the .asd file resides.
Previous: Other code in .asd files, Up: Defining systems with defsystem [Contents][Index]