Next: , Previous: A more involved example, Up: Defining systems with defsystem


5.3 The defsystem grammar

     system-definition := ( defsystem system-designator system-option* )
     
     system-option := :defsystem-depends-on system-list
                      | :class class-name (see discussion below)
                      | module-option
                      | option
     
     module-option := :components component-list
                      | :serial [ t | nil ]
                      | :if-component-dep-fails component-dep-fail-option
     
     option :=
             | :pathname pathname-specifier
             | :default-component-class class-name
             | :perform method-form
             | :explain method-form
             | :output-files method-form
             | :operation-done-p method-form
             | :depends-on ( dependency-def* )
             | :in-order-to ( dependency+ )
     
     
     system-list := ( simple-component-name* )
     
     component-list := ( component-def* )
     
     component-def  := ( component-type simple-component-name option* )
     
     component-type := :system | :module | :file | :static-file | other-component-type
     
     other-component-type := symbol-by-name (see Component types)
     
     dependency-def := simple-component-name
                    | ( :feature name )
                    | ( :version simple-component-name version-specifier)
     
     dependency := (dependent-op requirement+)
     requirement := (required-op required-component+)
                  | (feature feature-name)
     dependent-op := operation-name
     required-op := operation-name | feature
     
     simple-component-name := string
                           |  symbol
     
     pathname-specifier := pathname | string | symbol
     
     method-form := (operation-name qual lambda-list &rest body)
     qual := method qualifier
     
     component-dep-fail-option := :fail | :try-next | :ignore

5.3.1 Component names

Component names (simple-component-name) may be either strings or symbols.

5.3.2 Component types

Component type names, even if expressed as keywords, will be looked up by name in the current package and in the asdf package, if not found in the current package. So a component type my-component-type, in the current package my-system-asd can be specified as :my-component-type, or my-component-type.

5.3.3 System class names

A system class name will be looked up in the same way as a Component type (see above). Typically, one will not need to specify a system class name, unless using a non-standard system class defined in some ASDF extension, typically loaded through DEFSYSTEM-DEPENDS-ON, see below. For such class names in the ASDF package, we recommend that the :class option be specified using a keyword symbol, such as

     :class :MY-NEW-SYSTEM-SUBCLASS

This practice will ensure that package name conflicts are avoided. Otherwise, the symbol MY-NEW-SYSTEM-SUBCLASS will be read into the current package before it has been exported from the ASDF extension loaded by :defsystem-depends-on, causing a name conflict in the current package.

5.3.4 Defsystem depends on

The :defsystem-depends-on option to defsystem allows the programmer to specify another ASDF-defined system or set of systems that must be loaded before the system definition is processed. Typically this is used to load an ASDF extension that is used in the system definition.

5.3.5 Pathname specifiers

A pathname specifier (pathname-specifier) may be a pathname, a string or a symbol. When no pathname specifier is given for a component, which is the usual case, the component name itself is used.

If a string is given, which is the usual case, the string will be interpreted as a Unix-style pathname where / characters will be interpreted as directory separators. Usually, Unix-style relative pathnames are used (i.e. not starting with /, as opposed to absolute pathnames); they are relative to the path of the parent component. Finally, depending on the component-type, the pathname may be interpreted as either a file or a directory, and if it's a file, a file type may be added corresponding to the component-type, or else it will be extracted from the string itself (if applicable).

For instance, the component-type :module wants a directory pathname, and so a string "foo/bar" will be interpreted as the pathname #p"foo/bar/". On the other hand, the component-type :file wants a file of type lisp, and so a string "foo/bar" will be interpreted as the pathname #p"foo/bar.lisp", and a string "foo/bar.quux" will be interpreted as the pathname #p"foo/bar.quux.lisp". Finally, the component-type :static-file wants a file without specifying a type, and so a string "foo/bar" will be interpreted as the pathname #p"foo/bar", and a string "foo/bar.quux" will be interpreted as the pathname #p"foo/bar.quux".

ASDF does not interpret the string ".." to designate the parent directory. This string will be passed through to the underlying operating system for interpretation. We believe that this will work on all platforms where ASDF is deployed, but do not guarantee this behavior. A pathname object with a relative directory component of :up or :back is the only guaranteed way to specify a parent directory.

If a symbol is given, it will be translated into a string, and downcased in the process. The downcasing of symbols is unconventional, but was selected after some consideration. Observations suggest that the type of systems we want to support either have lowercase as customary case (Unix, Mac, windows) or silently convert lowercase to uppercase (lpns), so this makes more sense than attempting to use :case :common as argument to make-pathname, which is reported not to work on some implementations.

Pathname objects may be given to override the path for a component. Such objects are typically specified using reader macros such as #p or #.(make-pathname ...). Note however, that #p... is a shorthand for #.(parse-namestring ...) and that the behavior of parse-namestring is completely non-portable, unless you are using Common Lisp logical-pathnames (see Using logical pathnames, below). Pathnames made with #.(make-pathname ...) can usually be done more easily with the string syntax above. The only case that you really need a pathname object is to override the component-type default file type for a given component. Therefore, pathname objects should only rarely be used. Unhappily, ASDF 1 didn't properly support parsing component names as strings specifying paths with directories, and the cumbersome #.(make-pathname ...) syntax had to be used.

Note that when specifying pathname objects, ASDF does not do any special interpretation of the pathname influenced by the component type, unlike the procedure for pathname-specifying strings. On the one hand, you have to be careful to provide a pathname that correctly fulfills whatever constraints are required from that component type (e.g. naming a directory or a file with appropriate type); on the other hand, you can circumvent the file type that would otherwise be forced upon you if you were specifying a string.

5.3.6 Version specifiers

Version specifiers are parsed as period-separated lists of integers. I.e., in the example, 0.2.1 is to be interpreted, roughly speaking, as (0 2 1). In particular, version 0.2.1 is interpreted the same as 0.0002.1 and is strictly version-less-than version 0.20.1, even though the two are the same when interpreted as decimal fractions.

System definers are encouraged to use version identifiers of the form x.y.z for major version, minor version (compatible API) and patch level.

See Common attributes of components.

5.3.7 Using logical pathnames

We do not generally recommend the use of logical pathnames, especially not so to newcomers to Common Lisp. However, we do support the use of logical pathnames by old timers, when such is their preference.

To use logical pathnames, you will have to provide a pathname object as a :pathname specifier to components that use it, using such syntax as #p"LOGICAL-HOST:absolute;path;to;component.lisp".

You only have to specify such logical pathname for your system or some top-level component. Sub-components' relative pathnames, specified using the string syntax for names, will be properly merged with the pathnames of their parents. The specification of a logical pathname host however is not otherwise directly supported in the ASDF syntax for pathname specifiers as strings.

The asdf-output-translation layer will avoid trying to resolve and translate logical pathnames. The advantage of this is that you can define yourself what translations you want to use with the logical pathname facility. The disadvantage is that if you do not define such translations, any system that uses logical pathnames will behave differently under asdf-output-translations than other systems you use.

If you wish to use logical pathnames you will have to configure the translations yourself before they may be used. ASDF currently provides no specific support for defining logical pathname translations.

Note that the reasons we do not recommend logical pathnames are that (1) there is no portable way to set up logical pathnames before they are used, (2) logical pathnames are limited to only portably use a single character case, digits and hyphens. While you can solve the first issue on your own, describing how to do it on each of fifteen implementations supported by ASDF is more than we can document. As for the second issue, mind that the limitation is notably enforced on SBCL, and that you therefore can't portably violate the limitations but must instead define some encoding of your own and add individual mappings to name physical pathnames that do not fit the restrictions. This can notably be a problem when your Lisp files are part of a larger project in which it is common to name files or directories in a way that includes the version numbers of supported protocols, or in which files are shared with software written in different programming languages where conventions include the use of underscores, dots or CamelCase in pathnames.

5.3.8 Serial dependencies

If the :serial t option is specified for a module, ASDF will add dependencies for each child component, on all the children textually preceding it. This is done as if by :depends-on.

     :serial t
     :components ((:file "a") (:file "b") (:file "c"))

is equivalent to

     :components ((:file "a")
                  (:file "b" :depends-on ("a"))
                  (:file "c" :depends-on ("a" "b")))

5.3.9 Source location

The :pathname option is optional in all cases for systems defined via defsystem, and in the usual case the user is recommended not to supply it.

Instead, ASDF follows a hairy set of rules that are designed so that

  1. find-system will load a system from disk and have its pathname default to the right place.
  2. This pathname information will not be overwritten with *default-pathname-defaults* (which could be somewhere else altogether) if the user loads up the .asd file into his editor and interactively re-evaluates that form.

If a system is being loaded for the first time, its top-level pathname will be set to:

If a system is being redefined, the top-level pathname will be

5.3.10 if-component-dep-fails option

This option is only appropriate for module components (including systems), not individual source files.

For more information about this option, see Pre-defined subclasses of component.