Next: Controlling where ASDF searches for systems, Previous: Defining systems with defsystem, Up: Top
ASDF is designed in an object-oriented way from the ground up. Both a system's structure and the operations that can be performed on systems follow a extensible protocol.
This allows the addition of behaviours:
for example, cffi
adds support of special FFI description files
to interface with C libraries and of wrapper files to embed C code in Lisp;
abcl-jar
supports creating Java JAR archives in ABCL;
and poiu
supports for compiling code in parallel using background processes.
This chapter deals with component
s and operation
s.
A component
represents an individual source file or a group of source files,
and the things that get transformed into.
A system
is a component at the top level of the component hierarchy.
A source-file
is a component representing a single source-file
and the successive output files into which it is transformed.
A module
is an intermediate component itself grouping several other components,
themselves source-files or further modules.
An Operation
represents a transformation that can be performed on a component,
turning them from source files to intermediate results to final outputs.
A pair of an operation
and a component
is called an action
.
An action
represents a particular build step to be perform
ed,
after all its dependencies have been fulfilled.
In the ASDF model, actions depend on other actions.
The term action itself was used by Kent Pitman in his old article,
but was only used by ASDF hackers starting with the ASDF 2;
but the concept is ubiquitous since the very beginning of ASDF 1,
though previously implicit.
Then, there are many functions available
to users, extenders and implementers of ASDF
to use, define or implement the activities
that are part of building your software.
Though they manipulate action
s,
most of these functions do not take as an argument
a reified pair (a CONS cell) of an operation and a component;
instead, they usually take two separate arguments,
which allows to take advantage of the power CLOS-style multiple dispatch
for fun and profit.
There are many hooks in which to add functionality, by customizing the behavior of existing functions.
Last but not least is the notion of dependency between two actions.
The structure of dependencies between actions is
a directed dependency graph.
ASDF is invoked by being told to operate
with some operation on some toplevel system;
it will then traverse the graph and build a plan
that follows its structure.
To be successfully buildable, this graph of actions but be acyclic.
If, as a user, extender or implementer of ASDF, you fail
to keep the dependency graph without cycles,
ASDF will fail loudly as it eventually finds one.
To clearly distinguish the direction of dependencies,
ASDF 3 uses the words requiring and required
as applied to an action depending on the other:
the requiring action depends-on
the completion of all required actions
before it may itself be perform
ed.
Using the defsystem
syntax, users may easily express
direct dependencies along the graph of the object hierarchy:
between a component and its parent, its children, and its siblings.
By defining custom CLOS methods, you can express more elaborate dependencies as you wish.
Most common operations, such as load-op
, compile-op
or load-source-op
are automatically propagate “downward” the component hierarchy and are “covariant” with it:
to act the operation on the parent module, you must first act it on all the children components,
with the action on the parent being parent of the action on each child.
Other operations, such as prepare-op
and prepare-source-op
(introduced in ASDF 3) are automatically propagated “upward” the component hierarchy
and are “contravariant” with it:
to perform the operation of preparing for compilation of a child component,
you must perform the operation of preparing for compilation of its parent component, and so on,
ensuring that all the parent's dependencies are (compiled and) loaded
before the child component may be compiled and loaded.
Yet other operations, such as test-op
or load-fasl-op
remain at the system level, and are not propagated along the hierarchy,
but instead do something global on the system.