ASDF includes several additional features that are generally useful for system definition and development.
When declaring a component (system, module, file),
you can specify a keyword argument
If left unspecified (and therefore unbound),
the value will be inherited from the parent component if any,
or with a default of
if no value is specified in any transitive parent.
The argument must be a either
nil, a fbound symbol,
a lambda-expression (e.g.
(lambda (thunk) ...(funcall thunk ...) ...))
a function object (e.g. using
#.#' but that's discouraged
because it prevents the introspection done by e.g. asdf-dependency-grovel),
or a string that when
read yields a symbol or a lambda-expression.
nil means the normal compile-file function will be called.
A non-nil value designates a function of one argument
that will be called with a function that will
compile-file* with various arguments;
the around-compile hook may supply additional keyword arguments
to pass to that call to
One notable argument that is heeded by
a function called when the compilation was otherwise a success,
with the same arguments as
the function shall return true if the compilation
and its resulting compiled file respected all system-specific invariants,
and false (
nil) if it broke any of those invariants;
it may issue warnings or errors before it returns
(NB: The ability to pass such extra flags
is only available starting with ASDF 2.22.3.)
This feature is notably exercised by asdf-finalizers.
By using a string, you may reference
a function, symbol and/or package
that will only be created later during the build, but
isn't yet present at the time the defsystem form is evaluated.
However, if your entire system is using such a hook, you may have to
explicitly override the hook with
nil for all the modules and files
that are compiled before the hook is defined.
Using this hook, you may achieve such effects as: locally renaming packages, binding *readtables* and other syntax-controlling variables, handling warnings and other conditions, proclaiming consistent optimization settings, saving code coverage information, maintaining meta-data about compilation timings, setting gensym counters and PRNG seeds and other sources of non-determinism, overriding the source-location and/or timestamping systems, checking that some compile-time side-effects were properly balanced, etc.
Note that there is no around-load hook. This is on purpose.
Some implementations such as ECL, GCL or MKCL link object files,
which allows for no such hook.
Other implementations allow for concatenating FASL files,
which doesn't allow for such a hook either.
We aim to discourage something that's not portable,
and has some dubious impact on performance and semantics
even when it is possible.
Things you might want to do with an around-load hook
are better done around-compile,
though it may at times require some creativity
(see e.g. the
Starting with ASDF 2.21, components accept a
so authors may specify which character encoding should be used
to read and evaluate their source code.
When left unspecified, the encoding is inherited
from the parent module or system;
if no encoding is specified at any point,
:autodetect is assumed.
By default, only
:autodetect are accepted.
:autodetect, the default, calls
*encoding-detection-hook* which by default always returns
*default-encoding* which itself defaults to
In other words, there now are plenty of extension hooks, but
by default ASDF follows the backwards compatible behavior
of using whichever
:default encoding your implementation uses,
which itself may or may not vary based on environment variables
and other locale settings.
In practice this means that only source code that only uses ASCII
is guaranteed to be read the same on all implementations
independently from any user setting.
Additionally, for backward-compatibility with older versions of ASDF
and/or with implementations that do not support unicode and its many encodings,
you may want to use
the reader conditionals
to protect any
:encoding encoding statement
:asdf-unicode will be present in
only if you're using a recent ASDF
on an implementation that supports unicode.
We recommend that you avoid using unprotected
until after ASDF 2.21 or later becomes widespread, hopefully by the end of 2012.
While it offers plenty of hooks for extension,
and one such extension is being developed (see below),
ASDF itself only recognizes one encoding beside
and that is
:utf-8, which is the de facto standard,
already used by the vast majority of libraries that use more than ASCII.
On implementations that do not support unicode,
:asdf-unicode is absent, and
:default external-format is used
to read even source files declared as
On these implementations, non-ASCII characters
intended to be read as one CL character
may thus end up being read as multiple CL characters.
In most cases, this shouldn't affect the software's semantics:
comments will be skipped just the same, strings with be read and printed
with slightly different lengths, symbol names will be accordingly longer,
but none of it should matter.
But a few systems that actually depend on unicode characters
may fail to work properly, or may work in a subtly different way.
See for instance
We invite you to embrace UTF-8
as the encoding for non-ASCII characters starting today,
even without any explicit specification in your
Indeed, on some implementations and configurations,
UTF-8 is already the
and loading your code may cause errors if it is encoded in anything but UTF-8.
Therefore, even with the legacy behavior,
non-UTF-8 is guaranteed to break for some users,
whereas UTF-8 is pretty much guaranteed not to break anywhere
(provided you do not use a BOM),
although it might be read incorrectly on some implementations.
In the future, we intend to make
the default value of
to be enforced everywhere, so at least the code is guaranteed
to be read correctly everywhere it can be.
If you need non-standard character encodings for your source code,
use the extension system
asdf-encodings, by specifying
:defsystem-depends-on (:asdf-encodings) in your
This extension system will register support for more encodings using the
so you can explicitly specify
*encoding-detection-hook* it will also
eventually implement some autodetection of a file's encoding
from an emacs-style
-*- mode: lisp ; coding: latin1 -*- declaration,
or otherwise based on an analysis of octet patterns in the file.
At this point, asdf-encoding only supports the encodings
that are supported as part of your implementation.
Since the list varies depending on implementations,
we once again recommend you use
which is the most portable (next is
If you're not using a version of Quicklisp that has it,
you may get the source for
asdf-encodings using git:
git clone git://common-lisp.net/projects/asdf/asdf-encodings.git
git clone ssh://common-lisp.net/project/asdf/git/asdf-encodings.git.
You can also browse the repository on
In the future, we intend to change the default
:utf-8, which is already the de facto standard
for most libraries that use non-ASCII characters:
utf-8 works everywhere and was backhandedly enforced by
a lot of people using SBCL and utf-8 and sending reports to authors
so they make their packages compatible.
A survey showed only about a handful few libraries
are incompatible with non-UTF-8, and then, only in comments,
and we believe that authors will adopt UTF-8 when prompted.
See the April 2012 discussion on the asdf-devel mailing-list.
For backwards compatibility with users who insist on a non-UTF-8 encoding,
but cannot immediately transition to using
(maybe because it isn't ready), it will still be possible to use
:encoding :default option in your
to restore the behavior of ASDF 2.20 and earlier.
This shouldn't be required in libraries,
because user pressure as mentioned above will already have pushed
library authors towards using UTF-8;
but authors of end-user programs might care.
When you use
asdf-encodings, any further loaded
will use the autodetection algorithm to determine its encoding;
yet if you depend on this detection happening,
you may want to explicitly load
asdf-encodings early in your build,
for by the time you can use
it is already too late to load it.
In practice, this means that the
is usually used for
Currently, this defaults to
:default for backwards compatibility,
and that means that you shouldn't rely on non-ASCII characters in a .asd file.
Since component (path)names are the only real data in these files,
and non-ASCII characters are not very portable for file names,
this isn't too much of an issue.
We still encourage you to use either plain ASCII or UTF-8
as we intend to make
:utf-8 the default encoding in the future.
This might matter, for instance, in meta-data about author's names.
These functions are exported by ASDF for your convenience.
It's often handy to locate a file relative to some system. The
system-relative-pathnamefunction meets this need.
It takes two mandatory arguments system and name and a keyword argument type: system is name of a system, whereas name and optionally type specify a relative pathname, interpreted like a component pathname specifier by
coerce-pathname. See Pathname specifiers.
It returns a pathname built from the location of the system's source directory and the relative pathname. For example:> (asdf:system-relative-pathname 'cl-ppcre "regex.data") #P"/repository/other/cl-ppcre/regex.data"
ASDF does not provide a turnkey solution for locating data (or other miscellaneous) files that are distributed together with the source code of a system. Programmers can use
system-source-directoryto find such files. Returns a pathname object. The system-designator may be a string, symbol, or ASDF system object.
It is sometimes useful to force recompilation of a previously loaded system. In these cases, it may be useful to
(asdf:clear-system :foo)to remove the system from the table of currently loaded systems; the next time the system
fooor one that depends on it is re-loaded,
foowill then be loaded again. Alternatively, you could touch
foo.asdor remove the corresponding fasls from the output file cache. (It was once conceived that one should provide a list of systems the recompilation of which to force as the
:forcekeyword argument to
load-system; but this has never worked, and though the feature was fixed in ASDF 2.000, it remains
cerror'ed out as nobody ever used it.)
Note that this does not and cannot by itself undo the previous loading of the system. Common Lisp has no provision for such an operation, and its reliance on irreversible side-effects to global datastructures makes such a thing impossible in the general case. If the software being re-loaded is not conceived with hot upgrade in mind, this re-loading may cause many errors, warnings or subtle silent problems, as packages, generic function signatures, structures, types, macros, constants, etc. are being redefined incompatibly. It is up to the user to make sure that reloading is possible and has the desired effect. In some cases, extreme measures such as recursively deleting packages, unregistering symbols, defining methods on
update-instance-for-redefined-classand much more are necessary for reloading to happen smoothly. ASDF itself goes through notable pains to make such a hot upgrade possible with respect to its own code, and what it does is ridiculously complex; look at the beginning of asdf.lisp to see what it does.
A system with name name, created by
make-instancewith extra keys keys (e.g.
:version), is registered as preloaded. That is, its code has already been loaded into the current image, and if at some point some other system
:depends-onit yet no source code is found, it is considered as already provided, and ASDF will not raise a
This function is particularly useful if you distribute your code as fasls with either
monolithic-fasl-op, and want to register systems so that dependencies will work uniformly whether you're using your software from source or from fasl.
This function is obsolete and present only for the sake of backwards-compatibility: “If it's not backwards, it's not compatible”. We strongly discourage its use. Its current behavior is only well-defined on Unix platforms (which include MacOS X and cygwin). On Windows, anything goes. The following documentation is only for the purpose of your migrating away from it in a way that preserves semantics.
Instead we recommend the use
run-program, described in the next section, and available as part of ASDF since ASDF 3.
run-shell-commandtakes as arguments a format
control-stringand arguments to be passed to
formatafter this control-string to produce a string. This string is a command that will be evaluated with a POSIX shell if possible; yet, on Windows, some implementations will use CMD.EXE, while others (like SBCL) will make an attempt at invoking a POSIX shell (and fail if it is not present).
The below functions are not exported by ASDF itself, but by UIOP, available since ASDF 3. Some of them have precursors in ASDF 2, but we recommend you rely on ASDF 3 for active developments. UIOP provides many, many more utility functions, and we recommend you read its README and sources for more information.
Coerce NAME into a PATHNAME using standard Unix syntax.
Unix syntax is used whether or not the underlying system is Unix; on such non-Unix systems it is only usable but for relative pathnames; but especially to manipulate relative pathnames portably, it is of crucial to possess a portable pathname syntax independent of the underlying OS. This is what
parse-unix-namestringprovides, and why we use it in ASDF.
When given a
pathnameobject, just return it untouched. When given
nil, just return
nil. When given a non-null
symbol, first downcase its name and treat it as a string. When given a
string, portably decompose it into a pathname as below.
#\/separates directory components.
#\/-separated substring is interpreted as follows: 1- If type is
:directoryor ensure-directory is true, the string is made the last directory component, and its
nil. if the string is empty, it's the empty pathname with all slots
nil. 2- If type is
nil, the substring is a file-namestring, and its
typeare separated by
split-name-type. 3- If type is a string, it is the given
type, and the whole string is the
Directory components with an empty name the name
.are removed. Any directory named
..is read as dot-dot, which must be one of
:upand defaults to
versioncomponents are taken from defaults, which itself defaults to
*nil-pathname*, also used if defaults is
nil. No host or device can be specified in the string itself, which makes it unsuitable for absolute pathnames outside Unix.
For relative pathnames, these components (and hence the defaults) won't matter if you use
merge-pathnames*but will matter if you use
merge-pathnames, which is an important reason to always use
Arbitrary keys are accepted, and the parse result is passed to
ensure-pathnamewith those keys, removing type, defaults and dot-dot. When you're manipulating pathnames that are supposed to make sense portably even though the OS may not be Unixish, we recommend you use
:want-relative tto throw an error if the pathname is absolute
This function is a replacement for
merge-pathnamesthat uses the host and device from the defaults rather than the specified pathname when the latter is a relative pathname. This allows ASDF and its users to create and use relative pathnames without having to know beforehand what are the host and device of the absolute pathnames they are relative to.
This function takes a pathname and a subpath and a type. If subpath is already a
pathnameobject (not namestring), and is an absolute pathname at that, it is returned unchanged; otherwise, subpath is turned into a relative pathname with given type as per
:want-relative t :typetype, then it is merged with the
pathname-directory-pathnameof pathname, as per
We strongly encourage the use of this function for portably resolving relative pathnames in your code base.
This function returns
nilif the base pathname is
nil, otherwise acts like
if-input-does-not-exist if-output-exists if-error-output-exists element-type external-format &allow-other-keys
run-programtakes a command argument that is either a list of a program name or path and its arguments, or a string to be executed by a shell. It spawns the command, waits for it to return, verifies that it exited cleanly (unless told not too below), and optionally captures and processes its output. It accepts many keyword arguments to configure its behavior.
run-programreturns three values: the first for the output, the second for the error-output, and the third for the return value. (Beware that before ASDF 22.214.171.124, it didn't handle input or error-output, and returned only one value, the one for the output if any handler was specified, or else the exit code; please upgrade ASDF, or at least UIOP, to rely on the new enhanced behavior.)
output is its most important argument; it specifies how the output is captured and processed. If it is
nil, then the output is redirected to the null device, that will discard it. If it is
:interactive, then it is inherited from the current process (beware: this may be different from your *standard-output*, and under SLIME will be on your
*inferior-lisp*buffer). If it is
t, output goes to your current *standard-output* stream. Otherwise, output should be a value that is a suitable first argument to
slurp-input-stream(see below), or a list of such a value and keyword arguments. In this case,
run-programwill create a temporary stream for the program output; the program output, in that stream, will be processed by a call to
slurp-input-stream, using output as the first argument (or if it's a list the first element of output and the rest as keywords). The primary value resulting from that call (or
nilif no call was needed) will be the first value returned by
run-program. E.g., using
:output :stringwill have it return the entire output stream as a string. And using
:output '(:string :stripped t)will have it return the same string stripped of any ending newline.
error-output is similar to output, except that the resulting value is returned as the second value of
tdesignates the *error-output*. Also
:outputmeans redirecting the error output to the output stream, in which case
input is similar to output, except that
vomit-output-streamis used, no value is returned, and
tdesignates the *standard-input*.
external-formatare passed on to your Lisp implementation, when applicable, for creation of the output stream.
One and only one of the stream slurping or vomiting may or may not happen in parallel in parallel with the subprocess, depending on options and implementation, and with priority being given to output processing. Other streams are completely produced or consumed before or after the subprocess is spawned, using temporary files.
force-shellforces evaluation of the command through a shell, even if it was passed as a list rather than a string. If a shell is used, it is /bin/sh on Unix or CMD.EXE on Windows, except on implementations that (erroneously, IMNSHO) insist on consulting
run-programto not raise an error if the spawned program exits in error. Following POSIX convention, an error is anything but a normal exit with status code zero. By default, an error of type
subprocess-erroris raised in this case.
run-programworks on all platforms supported by ASDF, except Genera. See the source code for more documentation.
It's a generic function of two arguments, a target object and an input stream, and accepting keyword arguments. Predefined methods based on the target object are as follow:
If the object is a function, the function is called with the stream as argument.
If the object is a cons, its first element is applied to its rest appended by a list of the input stream.
If the object is an output stream, the contents of the input stream are copied to it. If the linewise keyword argument is provided, copying happens line by line, and an optional prefix is printed before each line. Otherwise, copying happen based on a buffer of size buffer-size, using the specified element-type.
If the object is
:string, the content is captured into a string. Accepted keywords include the element-type and a flag stripped, which when true causes any single line ending to be removed as per
If the object is
:lines, the content is captured as a list of strings, one per line, without line ending. If the count keyword argument is provided, it is a maximum count of lines to be read.
If the object is
:line, the content is capture as with
:linesabove, and then its sub-object is extracted with the at argument, which defaults to
0, extracting the first line. A number will extract the corresponding line. See the documentation for
If the object is
:forms, the content is captured as a list of S-expressions, as read by the Lisp reader. If the count argument is provided, it is a maximum count of lines to be read. We recommend you control the syntax with such macro as
If the object is
:form, the content is capture as with
:formsabove, and then its sub-object is extracted with the at argument, which defaults to
0, extracting the first form. A number will extract the corresponding form. See the documentation for
uiop:access-at. We recommend you control the syntax with such macro as