Next: , Previous: Error handling, Up: Top


10 Miscellaneous additional functionality

ASDF includes several additional features that are generally useful for system definition and development.

10.1 Controlling file compilation

When declaring a component (system, module, file), you can specify a keyword argument :around-compile function. If left unspecified, the value will be inherited from the parent component if any, or with a default of nil 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 thunk for calling the compile-file function with proper arguments.

Note that 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.

10.2 Miscellaneous Exported Functions

— Function: coerce-pathname name &key type defaults

This function (available starting with ASDF 2.012.11) takes an argument, and portably interprets it as a pathname. If the argument name is a pathname or nil, it is passed through; if it's a symbol, it's interpreted as a string by downcasing it; if it's a string, it is first separated using / into substrings; the leading substrings denote subdirectories of a relative pathname. If type is :directory or the string ends with /, the last substring is also a subdirectory; if type is a string, it is used as the type of the pathname, and the last substring is the name component of the pathname; if type is nil, the last substring specifies both name and type components of the pathname, with the last . separating them, or only the name component if there's no last . or if there is only one dot and it's the first character. The host, device and version components come from defaults, which defaults to *default-pathname-defaults*; but that shouldn't matter if you use merge-pathnames*.

— Function: merge-pathnames* &key specified defaults

This function is a replacement for merge-pathnames that 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.

— Function: system-relative-pathname system name &key type

It's often handy to locate a file relative to some system. The system-relative-pathname function 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"
— Function: system-source-directory system-designator

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-directory to find such files. Returns a pathname object. The system-designator may be a string, symbol, or ASDF system object.

— Function: clear-system system-designator

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 foo or one that depends on it is re-loaded, foo will then be loaded again. Alternatively, you could touch foo.asd or 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 :force keyword 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-class and 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.

— Function: run-shell-command

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 includes MacOS X and cygwin). On Windows, anything goes.

Instead we recommend the use of such a function as xcvb-driver:run-program/process-output-stream from the xcvb-driver system that is distributed with XCVB: http://common-lisp.net/project/xcvb. It's only alternative that supports as many implementations and operating systems as ASDF does, and provides well-defined behavior outside Unix (i.e. on Windows). (The only unsupported exception is Genera, since on it run-shell-command doesn't make sense anyway on that platform).

This function takes as arguments a format control-string and arguments to be passed to format after 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).