Let’s illustrate some more involved uses of
defsystem via a
slightly convoluted example:
(in-package :asdf-user) (defsystem "foo" :version (:read-file-form "variables" :at (3 2)) :components ((:file "package") (:file "variables" :depends-on ("package")) (:module "mod" :depends-on ("package") :serial t :components ((:file "utils") (:file "reader") (:file "cooker") (:static-file "data.raw")) :output-files (compile-op (o c) (list "data.cooked")) :perform (compile-op :after (o c) (cook-data :in (component-pathname (find-component c "data.raw")) :out (first (output-files o c))))) (:file "foo" :depends-on ("mod")))) (defmethod action-description ((o compile-op) (c (eql (find-component "foo" "mod")))) "cooking data")
Here are some notes about this example:
foo. It also contains other Lisp forms, which we’ll examine below.
"mod", which is a collection of three Lisp source files utils.lisp, reader.lisp, cooker.lisp and data.raw
:static-filedoes not have an implicit file type, unlike the Lisp source files.
:pathnameoption in The defsystem grammar).
:serial tsays that each sub-component of
moddepends on the previous components, so that cooker.lisp depends-on utils.lisp, which depends-on reader.lisp. Also data.raw depends on all of them, but that doesn’t matter since it’s a static file; on the other hand, if it appeared first, then all the Lisp files would be recompiled when the data is modified, which is probably not what is desired in this case.
:output-files (compile-op (o c) (list "data.cooked")) :perform (compile-op :after (o c) (cook-data :in (component-pathname (find-component c "data.raw")) :out (first (output-files o c))))
has the effect of
(defmethod output-files ((o compile-op) (c (eql ...))) (list "data.cooked")) (defmethod perform :after ((o compile-op) (c (eql ...))) (cook-data :in (component-pathname (find-component c "data.raw")) :out (first (output-files o c))))
... is the component in question.
In this case
... would expand to something like
(find-component "foo" "mod")
defmethodwith a similar effect, because ASDF (as of ASDF 3.1.5) fails to accept inline-methods as above for
action-description, instead only supporting the deprecated
(in-package :asdf-user), but it is actually redundant, not necessary and not recommended. But yet more complex cases (also not recommended) may usefully use an
cl:load, and neither should you. You should let ASDF find and load them when you operate on systems. If you somehow must load a .asd file, use the same function
asdf:load-asdthat ASDF uses. Among other things, it already binds the
asdf-user. Recent versions of SLIME (2013-02 and later) know to do that when you C-c C-k when you use the
in-packageform if you’re keeping things simple. You should only use
in-package(and before it, a
defpackage) when you’re going to define new classes, functions, variables, macros, etc., in the
.asdfile, and want to thereby avoid name clashes. Manuals for old versions of ASDF recommended use of such an idiom in .asd files, but as of ASDF 3, we recommend that you don’t do that anymore, and instead define any ASDF extensions in their own system, on which you can then declare a dependency using
:defsystem-depends-on. See The defsystem grammar.
uiopbeing available in
.asdfiles — most importantly including
defsystem. It is therefore redundant and in bad taste to use a package-prefixed
asdf:defsystemsymbol in a .asd file. Just use
(defsystem ...). Only package-prefix it when somehow dynamically generating system definitions from a package that doesn’t already use the ASDF package.
asdf-useris actually only available starting since ASDF 3, but then again, ASDF 1 and 2 did crazy things with packages that ASDF 3 has stopped doing9, and since all implementations provide ASDF 3, you shouldn’t care about compatibility with ASDF 2. We do not support ASDF 2 anymore, and we recommend that neither should you.
uiop, whereas in earlier variants of ASDF 3 it only used
uiop/package. We recommend you either prefix use of UIOP functions with the package prefix
uiop:, or make sure your system
:depends-on ((:version "asdf" "3.1.2"))or has a
#-asdf3.1 (error "MY-SYSTEM requires ASDF 3.1.2").
(defparameter *foo-version* "5.6.7").
ASDF 1 and 2 (up until 2.26)
used to dynamically create and delete temporary packages
one for each .asd file, in a misguided attempt to thereby reduce name clashes;
but it failed at that goal and only made things more complex.
ASDF 3 just uses a shared package
and relies on the usual Common Lisp conventions to avoid clashes.
As far as package oddities go, you may just notice that
asdf-user package also uses
a variant of the
common-lisp package that papers over
deficiencies in more obscure Common Lisp implementations;
but unless you care about Corman Lisp, GCL, Genera or MCL, you shouldn’t be concerned.