Commit ac013b1b authored by Robert Goldman's avatar Robert Goldman

Merge branch 'doc-update' into 'master'

Doc update

I'm slowly proofreading the code of ASDF and adding more comments and docstrings. That will take a few weeks to complete. Here is what I have so far. You may merge at any point. This branch ought to not modify any code as such, only comments, docstrings, manual sections, and other non-code-generating parts of the repository.

See merge request !24
parents 67172768 817e6ffd
......@@ -4,8 +4,9 @@
** Already, swank-asdf doesn't support anything older than 2.014.6
(as provided by the first 2011 iteration of Quicklisp), and
I (fare) am pushing for swank-asdf to not support anything older
than 3.0 (since no maintained implementation has anything older,
with the LispWorks 7.0 release being last to upgrade, in May 2015).
than 3.1.2 (since no maintained implementation has anything older,
with the LispWorks 7.0 release being last to upgrade, in May 2015;
or CLISP hg in May 2016, though it hasn't been released since 2010).
** Maybe remove old versions from upgrade tests; or maybe not:
if we support old versions in any way,
it should be for upgrade only, and "punt" is acceptable.
......@@ -13,6 +14,8 @@
Clear all the code in the header, and/or
move a few elements to asdf/upgrade.
** Upgrade tests might be split in two test sets: short and long.
** Make tests stateless and/or make any modifications private,
so that they can be run in parallel.
* Moving toward cross-compilation (ASDF 3.2? 4?)
This would allow to get most of the benefits of XCVB
......
This diff is collapsed.
......@@ -20,6 +20,10 @@
(in-package :asdf/backward-interface)
(with-upgradability ()
;; These conditions from ASDF 1 and 2 are used by many packages in Quicklisp;
;; but ASDF3 replaced them with somewhat different variants of uiop:compile-condition
;; that do not involve ASDF actions.
;; TODO: find the offenders and stop them.
(define-condition operation-error (error) ;; Bad, backward-compatible name
;; Used by SBCL, cffi-tests, clsql-mysql, clsql-uffi, qt, elephant, uffi-tests, sb-grovel
((component :reader error-component :initarg :component)
......@@ -32,16 +36,37 @@
(define-condition compile-warned (compile-error) ())
(defun component-load-dependencies (component)
"DEPRECATED. Please use COMPONENT-SIDEWAY-DEPENDENCIES instead."
;; Old deprecated name for the same thing. Please update your software.
(component-sideway-dependencies component))
(defgeneric operation-forced (operation)) ;; Used by swank.asd for swank-loader.
(defgeneric operation-forced (operation)
(:documentation "DEPRECATED. Assume it's (constantly t) instead."))
;; This method exists for backward compatibility with swank.asd, its only user,
;; that still uses it as of 2016-09-21.
;;
;; The magic PERFORM method in swank.asd only actually loads swank if it sees that
;; the operation was forced. But except for the first time, the only reason the action
;; would be performed to begin with is because it was forced; and the first time over,
;; it doesn't hurt that :reload t :delete t should be used. So the check is redundant.
;; More generally, if you have to do something when the operation was forced,
;; you should also do it when not, and vice-versa, because it really shouldn't matter.
;; Thus, the backward-compatible thing to do is to always return T.
;;
;; TODO: change this function to a defun that always returns T.
(defmethod operation-forced ((o operation)) (getf (operation-original-initargs o) :force))
(defgeneric operation-on-warnings (operation))
(defgeneric operation-on-failure (operation))
(defgeneric (setf operation-on-warnings) (x operation))
(defgeneric (setf operation-on-failure) (x operation))
;; These old interfaces from ASDF1 have never been very meaningful
;; but are still used in obscure places.
(defgeneric operation-on-warnings (operation)
(:documentation "DEPRECATED. Please use UIOP:*COMPILE-FILE-WARNINGS-BEHAVIOUR* instead."))
(defgeneric operation-on-failure (operation)
(:documentation "DEPRECATED. Please use UIOP:*COMPILE-FILE-FAILURE-BEHAVIOUR* instead."))
(defgeneric (setf operation-on-warnings) (x operation)
(:documentation "DEPRECATED. Please SETF UIOP:*COMPILE-FILE-WARNINGS-BEHAVIOUR* instead."))
(defgeneric (setf operation-on-failure) (x operation)
(:documentation "DEPRECATED. Please SETF UIOP:*COMPILE-FILE-FAILURE-BEHAVIOUR* instead."))
(defmethod operation-on-warnings ((o operation))
*compile-file-warnings-behaviour*)
(defmethod operation-on-failure ((o operation))
......@@ -55,15 +80,17 @@
;; As of 2.014.8, we mean to make this function obsolete,
;; but that won't happen until all clients have been updated.
;;(cerror "Use ASDF:SYSTEM-SOURCE-FILE instead"
"Function ASDF:SYSTEM-DEFINITION-PATHNAME is obsolete.
It used to expose ASDF internals with subtle differences with respect to
user expectations, that have been refactored away since.
We recommend you use ASDF:SYSTEM-SOURCE-FILE instead
for a mostly compatible replacement that we're supporting,
or even ASDF:SYSTEM-SOURCE-DIRECTORY or ASDF:SYSTEM-RELATIVE-PATHNAME
"DEPRECATED. This function used to expose ASDF internals with subtle
differences with respect to user expectations, that have been refactored
away since. We recommend you use ASDF:SYSTEM-SOURCE-FILE instead for a
mostly compatible replacement that we're supporting, or even
ASDF:SYSTEM-SOURCE-DIRECTORY or ASDF:SYSTEM-RELATIVE-PATHNAME
if that's whay you mean." ;;)
(system-source-file x))
;; TRAVERSE is the function used to compute a plan in ASDF 1 and 2.
;; It was never officially exposed but some people still used it.
(defgeneric* (traverse) (operation component &key &allow-other-keys)
(:documentation
"Generate and return a plan for performing OPERATION on COMPONENT.
......@@ -79,6 +106,7 @@ processed in order by OPERATE."))
;;;; ASDF-Binary-Locations compatibility
;; This remains supported for legacy user, but not recommended for new users.
;; We suspect there are no more legacy users in 2016.
(with-upgradability ()
(defun enable-asdf-binary-locations-compatibility
(&key
......
......@@ -23,22 +23,28 @@
(with-upgradability ()
(defclass bundle-op (basic-compile-op)
;; NB: use of instance-allocated slots for operations is DEPRECATED
;; and only supported in a temporary fashion for backward compatibility.
;; Supported replacement: Define slots on program-system instead.
((build-args :initarg :args :initform nil :accessor extra-build-args)
(name-suffix :initarg :name-suffix :initform nil)
(bundle-type :initform :no-output-file :reader bundle-type)
#+(or clasp ecl) (lisp-files :initform nil :accessor extra-object-files)))
#+(or clasp ecl) (lisp-files :initform nil :accessor extra-object-files))
(:documentation "base class for operations that bundle outputs from multiple components"))
(defclass monolithic-op (operation) ()
(:documentation "A MONOLITHIC operation operates on a system *and all of its
dependencies*. So, for example, a monolithic concatenate operation will
concatenate together a system's components and all of its dependencies, but a
simple concatenate operation will concatenate only the components of the system
itself.")) ;; operation on a system and its dependencies
itself."))
(defclass monolithic-bundle-op (monolithic-op bundle-op)
;; Old style way of specifying prologue and epilogue on ECL: in the monolithic operation
;; Old style way of specifying prologue and epilogue on ECL: in the monolithic operation.
;; DEPRECATED. Supported replacement: Define slots on program-system instead.
((prologue-code :initform nil :accessor prologue-code)
(epilogue-code :initform nil :accessor epilogue-code)))
(epilogue-code :initform nil :accessor epilogue-code))
(:documentation "operations that are both monolithic-op and bundle-op"))
(defclass program-system (system)
;; New style (ASDF3.1) way of specifying prologue and epilogue on ECL: in the system
......@@ -66,6 +72,7 @@ itself.")) ;; operation on a system and its dependencies
(:documentation "Abstract operation for linking files together"))
(defclass gather-op (bundle-op)
;; TODO: rename the slot and reader gather-op to gather-operation
((gather-op :initform nil :allocation :class :reader gather-op)
(gather-type :initform :no-output-file :allocation :class :reader gather-type))
(:documentation "Abstract operation for gathering many input files from a system"))
......@@ -73,6 +80,12 @@ itself.")) ;; operation on a system and its dependencies
(defun operation-monolithic-p (op)
(typep op 'monolithic-op))
;; Dependencies of a gather-op are the actions of the dependent operation
;; for all the (sorted) required components for loading the system.
;; Monolithic operations typically use lib-op as the dependent operation,
;; and all system-level dependencies as required components.
;; Non-monolithic operations typically use compile-op as the dependent operation,
;; and all transitive sub-components as required components (excluding other systems).
(defmethod component-depends-on ((o gather-op) (s system))
(let* ((mono (operation-monolithic-p o))
(deps
......@@ -85,16 +98,19 @@ itself.")) ;; operation on a system and its dependencies
`((,(make-operation (or (gather-op o) (if mono 'lib-op 'compile-op))) ,@deps)
,@(call-next-method))))
;; create a single fasl for the entire library
;; Create a single fasl for the entire library
(defclass basic-compile-bundle-op (bundle-op)
((gather-type :initform #-(or clasp ecl mkcl) :fasl #+(or clasp ecl mkcl) :object
:allocation :class)
(bundle-type :initform :fasl :allocation :class)))
(bundle-type :initform :fasl :allocation :class))
(:documentation "Base class for compiling into a bundle"))
;; Analog to prepare-op, for load-bundle-op and compile-bundle-op
(defclass prepare-bundle-op (sideway-operation)
((sideway-operation
:initform #+(or clasp ecl mkcl) 'load-bundle-op #-(or clasp ecl mkcl) 'load-op
:allocation :class)))
:allocation :class))
(:documentation "Operation class for loading the bundles of a system's dependencies"))
(defclass lib-op (link-op gather-op non-propagating-operation)
((gather-type :initform :object :allocation :class)
......@@ -104,7 +120,7 @@ for all the linkable object files associated with the system. Compare with DLL-O
On most implementations, these object files only include extensions to the runtime
written in C or another language with a compiler producing linkable object files.
On CLASP, ECL, MKCL, these object files also include the contents of Lisp files
On CLASP, ECL, MKCL, these object files _also_ include the contents of Lisp files
themselves. In any case, this operation will produce what you need to further build
a static runtime for your system, or a dynamic library to load in an existing runtime."))
......@@ -186,6 +202,7 @@ for all the linkable object files associated with the system or its dependencies
((bundle-type :initform :program))
(:documentation "create an executable file from the system and its dependencies"))
;; From the ASDF-internal bundle-type identifier, get a filesystem-usable pathname type.
(defun bundle-pathname-type (bundle-type)
(etypecase bundle-type
((or null string) ;; pass through nil or string literal
......@@ -212,6 +229,7 @@ for all the linkable object files associated with the system or its dependencies
((eql :program) ;; the type of an executable program
(os-cond ((os-unix-p) nil) ((os-windows-p) "exe")))))
;; Compute the output-files for a given bundle action
(defun bundle-output-files (o c)
(let ((bundle-type (bundle-type o)))
(unless (or (eq bundle-type :no-output-file) ;; NIL already means something regarding type.
......@@ -236,14 +254,19 @@ for all the linkable object files associated with the system or its dependencies
(setf *image-entry-point* (ensure-function (component-entry-point c)))))
(defclass compiled-file (file-component)
((type :initform #-(or clasp ecl mkcl) (compile-file-type) #+(or clasp ecl mkcl) "fasb")))
((type :initform #-(or clasp ecl mkcl) (compile-file-type) #+(or clasp ecl mkcl) "fasb"))
(:documentation "Class for a file that is already compiled,
e.g. as part of the implementation, of an outer build system that calls into ASDF,
or of opaque libraries shipped along the source code."))
(defclass precompiled-system (system)
((build-pathname :initarg :fasl)))
((build-pathname :initarg :fasl))
(:documentation "Class For a system that is delivered as a precompiled fasl"))
(defclass prebuilt-system (system)
((build-pathname :initarg :static-library :initarg :lib
:accessor prebuilt-system-static-library))))
:accessor prebuilt-system-static-library))
(:documentation "Class for a system delivered with a linkable static library (.a/.lib)")))
;;;
......@@ -259,6 +282,7 @@ for all the linkable object files associated with the system or its dependencies
&key (name-suffix nil name-suffix-p)
&allow-other-keys)
(declare (ignore initargs name-suffix))
;; TODO: make that class slots or methods, not instance slots
(unless name-suffix-p
(setf (slot-value instance 'name-suffix)
(unless (typep instance 'program-op)
......@@ -298,8 +322,8 @@ for all the linkable object files associated with the system or its dependencies
;;;
(with-upgradability ()
(defun direct-dependency-files (o c &key (test 'identity) (key 'output-files) &allow-other-keys)
;; This file selects output files from direct dependencies;
;; your component-depends-on method better gathered the correct dependencies in the correct order.
;; This function selects output files from direct dependencies;
;; your component-depends-on method must gather the correct dependencies in the correct order.
(while-collecting (collect)
(map-direct-dependencies
t o c #'(lambda (sub-o sub-c)
......@@ -315,6 +339,7 @@ for all the linkable object files associated with the system or its dependencies
o c :key 'output-files
:test (pathname-type-equal-function (bundle-pathname-type (gather-type o))))))
;; Find the operation that produces a given bundle-type
(defun select-bundle-operation (type &optional monolithic)
(ecase type
((:dll :shared-library)
......@@ -332,6 +357,7 @@ for all the linkable object files associated with the system or its dependencies
;; It must die, and so must any use of initargs in operation,
;; unless keys to the asdf-cache are substantially modified to accommodate for them.
;; Coordinate with the ECL maintainers to get them to stop using it.
;; SUPPORTED REPLACEMENT: Use program-op and program-system
(defun make-build (system &rest args &key (monolithic nil) (type :fasl)
(move-here nil move-here-p)
&allow-other-keys)
......@@ -538,7 +564,7 @@ for all the linkable object files associated with the system or its dependencies
#+mkcl (make-pathname :name name :type (bundle-pathname-type :lib) :defaults #p"sys:")
#+mkcl (make-pathname :name name :type (bundle-pathname-type :lib) :defaults #p"sys:contrib;")))))
(defun make-library-system (name &optional (pathname (system-module-pathname name)))
(defun make-prebuilt-system (name &optional (pathname (system-module-pathname name)))
"Creates a prebuilt-system if PATHNAME isn't NIL."
(when pathname
(make-instance 'prebuilt-system
......@@ -554,7 +580,7 @@ for all the linkable object files associated with the system or its dependencies
(and (system-source-directory x)
(list s)))
(if-let (p (system-module-pathname x))
(list (make-library-system x p)))))))
(list (make-prebuilt-system x p)))))))
`((,lib-op
,@(unless (no-uiop c)
(append (ensure-linkable-system "cmp")
......
......@@ -10,38 +10,53 @@
#:clear-configuration-and-retry #:retry))
(in-package :asdf/cache)
;;; The ASDF session cache is instrumental in achieving:
;;; The ASDF session cache is used to memoize some computations. It is instrumental in achieving:
;; * Consistency in the view of the world relied on by ASDF within a given session.
;; Inconsistencies in file stamps, definitions, etc., could cause infinite loops
;; Inconsistencies in file stamps, system definitions, etc., could cause infinite loops
;; (a.k.a. stack overflows) and other erratic behavior.
;; * Speed and reliability of ASDF, with fewer side-effects from access to the filesystem,
;; no expensive recomputations of transitive dependencies for input-files or output-files.
;; * Speed and reliability of ASDF, with fewer side-effects from access to the filesystem, and
;; no expensive recomputations of transitive dependencies for some input-files or output-files.
;; * Testability of ASDF with the ability to fake timestamps without actually touching files.
(with-upgradability ()
;; The session cache variable.
;; NIL when outside a session, an equal hash-table when inside a session.
(defvar *asdf-cache* nil)
;; Set a session cache entry for KEY to a list of values VALUE-LIST, when inside a session.
;; Return those values.
(defun set-asdf-cache-entry (key value-list)
(apply 'values
(if *asdf-cache*
(setf (gethash key *asdf-cache*) value-list)
value-list)))
(values-list (if *asdf-cache*
(setf (gethash key *asdf-cache*) value-list)
value-list)))
;; Unset the session cache entry for KEY, when inside a session.
(defun unset-asdf-cache-entry (key)
(when *asdf-cache*
(remhash key *asdf-cache*)))
;; Consult the session cache entry for KEY if present and in a session;
;; if not present, compute it by calling the THUNK,
;; and set the session cache entry accordingly, if in a session.
;; Return the values from the cache and/or the thunk computation.
(defun consult-asdf-cache (key &optional thunk)
(if *asdf-cache*
(multiple-value-bind (results foundp) (gethash key *asdf-cache*)
(if foundp
(apply 'values results)
(values-list results)
(set-asdf-cache-entry key (multiple-value-list (call-function thunk)))))
(call-function thunk)))
;; Syntactic sugar for consult-asdf-cache
(defmacro do-asdf-cache (key &body body)
`(consult-asdf-cache ,key #'(lambda () ,@body)))
;; Compute inside a ASDF session with a cache.
;; First, make sure an ASDF session is underway, by binding the session cache variable
;; to a new hash-table if it's currently null (or even if it isn't, if OVERRIDE is true).
;; Second, if a new session was started, establish restarts for retrying the overall computation.
;; Finally, consult the cache if a KEY was specified with the THUNK as a fallback when the cache
;; entry isn't found, or just call the THUNK if no KEY was specified.
(defun call-with-asdf-cache (thunk &key override key)
(let ((fun (if key #'(lambda () (consult-asdf-cache key thunk)) thunk)))
(if (and *asdf-cache* (not override))
......@@ -58,9 +73,14 @@
(format s (compatfmt "~@<Retry ASDF operation after resetting the configuration.~@:>")))
(clear-configuration)))))))
;; Syntactic sugar for call-with-asdf-cache
(defmacro with-asdf-cache ((&key key override) &body body)
`(call-with-asdf-cache #'(lambda () ,@body) :override ,override :key ,key))
;;; Define specific accessor for file (date) stamp.
;; Normalize a namestring for use as a key in the session cache.
(defun normalize-namestring (pathname)
(let ((resolved (resolve-symlinks*
(ensure-absolute-pathname
......@@ -68,15 +88,19 @@
'get-pathname-defaults))))
(with-pathname-defaults () (namestring resolved))))
;; Compute the file stamp for a normalized namestring
(defun compute-file-stamp (normalized-namestring)
(with-pathname-defaults ()
(safe-file-write-date normalized-namestring)))
;; Override the time STAMP associated to a given FILE in the session cache.
;; If no STAMP is specified, recompute a new one from the filesystem.
(defun register-file-stamp (file &optional (stamp nil stampp))
(let* ((namestring (normalize-namestring file))
(stamp (if stampp stamp (compute-file-stamp namestring))))
(set-asdf-cache-entry `(get-file-stamp ,namestring) (list stamp))))
;; Get or compute a memoized stamp for given FILE from the session cache.
(defun get-file-stamp (file)
(when file
(let ((namestring (normalize-namestring file)))
......
......@@ -46,26 +46,40 @@
(defgeneric component-name (component)
(:documentation "Name of the COMPONENT, unique relative to its parent"))
(defgeneric component-system (component)
(:documentation "Find the top-level system containing COMPONENT"))
(:documentation "Top-level system containing the COMPONENT"))
(defgeneric component-pathname (component)
(:documentation "Extracts the pathname applicable for a particular component."))
(:documentation "Pathname of the COMPONENT if any, or NIL."))
(defgeneric (component-relative-pathname) (component)
(:documentation "Returns a pathname for the component argument intended to be
interpreted relative to the pathname of that component's parent.
Despite the function's name, the return value may be an absolute
pathname, because an absolute pathname may be interpreted relative to
another pathname in a degenerate way."))
(defgeneric component-external-format (component))
(defgeneric component-encoding (component))
(defgeneric version-satisfies (component version))
(defgeneric component-version (component))
(defgeneric (setf component-version) (new-version component))
(defgeneric component-parent (component))
;; in ASDF4, rename that to component-specified-pathname ?
(:documentation "Specified pathname of the COMPONENT,
intended to be merged with the pathname of that component's parent if any, using merged-pathnames*.
Despite the function's name, the return value can be an absolute pathname, in which case the merge
will leave it unmodified."))
(defgeneric component-external-format (component)
(:documentation "The external-format of the COMPONENT.
By default, deduced from the COMPONENT-ENCODING."))
(defgeneric component-encoding (component)
(:documentation "The encoding of the COMPONENT. By default, only :utf-8 is supported.
Use asdf-encodings to support more encodings."))
(defgeneric version-satisfies (component version)
(:documentation "Check whether a COMPONENT satisfies the constraint of being at least as recent
as the specified VERSION, which must be a string of dot-separated natural numbers, or NIL."))
(defgeneric component-version (component)
(:documentation "Return the version of a COMPONENT, which must be a string of dot-separated
natural numbers, or NIL."))
(defgeneric (setf component-version) (new-version component)
(:documentation "Updates the version of a COMPONENT, which must be a string of dot-separated
natural numbers, or NIL."))
(defgeneric component-parent (component)
(:documentation "The parent of a child COMPONENT,
or NIL for top-level components (a.k.a. systems)"))
;; NIL is a designator for the absence of a component, in which case the parent is also absent.
(defmethod component-parent ((component null)) nil)
;; Backward compatible way of computing the FILE-TYPE of a component.
;; Deprecated: Backward compatible way of computing the FILE-TYPE of a component.
;; TODO: find users, have them stop using that, remove it for ASDF4.
(defgeneric (source-file-type) (component system))
(defgeneric (source-file-type) (component system)
(:documentation "DEPRECATED. Use the FILE-TYPE of a COMPONENT instead."))
(define-condition system-definition-error (error) ()
;; [this use of :report should be redundant, but unfortunately it's not.
......@@ -133,7 +147,8 @@ another pathname in a degenerate way."))
;; For backward-compatibility, this slot is part of component rather than of child-component. ASDF4: stop it.
(parent :initarg :parent :initform nil :reader component-parent)
(build-operation
:initarg :build-operation :initform nil :reader component-build-operation)))
:initarg :build-operation :initform nil :reader component-build-operation))
(:documentation "Base class for all components of a build"))
(defun component-find-path (component)
"Return a path from a root system to the COMPONENT.
......@@ -157,11 +172,12 @@ The return value is a list of component NAMES; a list of strings."
;; The tree typically but not necessarily follows the filesystem hierarchy.
(with-upgradability ()
(defclass child-component (component) ()
(:documentation "A CHILD-COMPONENT is a component that may be part of
(:documentation "A CHILD-COMPONENT is a COMPONENT that may be part of
a PARENT-COMPONENT."))
(defclass file-component (child-component)
((type :accessor file-type :initarg :type))) ; no default
((type :accessor file-type :initarg :type)) ; no default
(:documentation "a COMPONENT that represents a file"))
(defclass source-file (file-component)
((type :accessor source-file-explicit-type ;; backward-compatibility
:initform nil))) ;; NB: many systems have come to rely on this default.
......@@ -170,7 +186,8 @@ a PARENT-COMPONENT."))
(defclass java-source-file (source-file)
((type :initform "java")))
(defclass static-file (source-file)
((type :initform nil)))
((type :initform nil))
(:documentation "Component for a file to be included as is in the build output"))
(defclass doc-file (static-file) ())
(defclass html-file (doc-file)
((type :initform "html")))
......@@ -188,10 +205,13 @@ a PARENT-COMPONENT."))
:initform nil
:initarg :default-component-class
:accessor module-default-component-class))
(:documentation "A PARENT-COMPONENT is a component that may have
children.")))
(:documentation "A PARENT-COMPONENT is a component that may have children.")))
(with-upgradability ()
;; (Private) Function that given a PARENT component,
;; the list of children of which has been initialized,
;; compute the hash-table in slot children-by-name that allows to retrieve its children by name.
;; If ONLY-IF-NEEDED-P is defined, skip any (re)computation if the slot is already populated.
(defun compute-children-by-name (parent &key only-if-needed-p)
(unless (and only-if-needed-p (slot-boundp parent 'children-by-name))
(let ((hash (make-hash-table :test 'equal)))
......@@ -205,15 +225,22 @@ children.")))
(with-upgradability ()
(defclass module (child-component parent-component)
(#+clisp (components)))) ;; backward compatibility during upgrade only
(#+clisp (components)) ;; backward compatibility during upgrade only
(:documentation "A module is a intermediate component with both a parent and children,
typically but not necessarily representing the files in a subdirectory of the build source.")))
;;;; component pathnames
(with-upgradability ()
(defgeneric* (component-parent-pathname) (component))
(defgeneric* (component-parent-pathname) (component)
(:documentation "The pathname of the COMPONENT's parent, if any, or NIL"))
(defmethod component-parent-pathname (component)
(component-pathname (component-parent component)))
;; The default method for component-pathname tries to extract a cached precomputed
;; absolute-pathname from the relevant slot, and if not, computes it by merging the
;; component-relative-pathname (which should be component-specified-pathname, it can be absolute)
;; with the directory of the component-parent-pathname.
(defmethod component-pathname ((component component))
(if (slot-boundp component 'absolute-pathname)
(slot-value component 'absolute-pathname)
......@@ -227,6 +254,9 @@ children.")))
(setf (slot-value component 'absolute-pathname) pathname)
pathname)))
;; Default method for component-relative-pathname:
;; combine the contents of slot relative-pathname (from specified initarg :pathname)
;; with the appropriate source-file-type, which defaults to the file-type of the component.
(defmethod component-relative-pathname ((component component))
;; SOURCE-FILE-TYPE below is strictly for backward-compatibility with ASDF1.
;; We ought to be able to extract this from the component alone with FILE-TYPE.
......@@ -260,7 +290,11 @@ children.")))
;;;; around-compile-hook
(with-upgradability ()
(defgeneric around-compile-hook (component))
(defgeneric around-compile-hook (component)
(:documentation "An optional hook function that will be called with one argument, a thunk.
The hook function must call the thunk, that will compile code from the component, and may or may not
also evaluate the compiled results. The hook function may establish dynamic variable bindings around
this compilation, or check its results, etc."))
(defmethod around-compile-hook ((c component))
(cond
((slot-boundp c 'around-compile)
......@@ -289,6 +323,7 @@ children.")))
;;; all sub-components (of a given type)
(with-upgradability ()
(defun sub-components (component &key (type t))
"Compute the transitive sub-components of given COMPONENT that are of given TYPE"
(while-collecting (c)
(labels ((recurse (x)
(when (if-let (it (component-if-feature x)) (featurep it) t)
......
......@@ -22,27 +22,40 @@
;;; Concatenate sources
;;;
(with-upgradability ()
;; Base classes for both regular and monolithic concatenate-source operations
(defclass basic-concatenate-source-op (bundle-op)
((bundle-type :initform "lisp")))
(defclass basic-load-concatenated-source-op (basic-load-op selfward-operation) ())
(defclass basic-compile-concatenated-source-op (basic-compile-op selfward-operation) ())
(defclass basic-load-compiled-concatenated-source-op (basic-load-op selfward-operation) ())
(defclass concatenate-source-op (basic-concatenate-source-op non-propagating-operation) ())
;; Regular concatenate-source operations
(defclass concatenate-source-op (basic-concatenate-source-op non-propagating-operation) ()
(:documentation "Operation to concatenate all sources in a system into a single file"))
(defclass load-concatenated-source-op (basic-load-concatenated-source-op)
((selfward-operation :initform '(prepare-op concatenate-source-op) :allocation :class)))
((selfward-operation :initform '(prepare-op concatenate-source-op) :allocation :class))
(:documentation "Operation to load the result of concatenate-source-op as source"))
(defclass compile-concatenated-source-op (basic-compile-concatenated-source-op)
((selfward-operation :initform '(prepare-op concatenate-source-op) :allocation :class)))
((selfward-operation :initform '(prepare-op concatenate-source-op) :allocation :class))
(:documentation "Operation to compile the result of concatenate-source-op"))
(defclass load-compiled-concatenated-source-op (basic-load-compiled-concatenated-source-op)
((selfward-operation :initform '(prepare-op compile-concatenated-source-op) :allocation :class)))
((selfward-operation :initform '(prepare-op compile-concatenated-source-op) :allocation :class))
(:documentation "Operation to load the result of compile-concatenated-source-op"))
(defclass monolithic-concatenate-source-op (basic-concatenate-source-op monolithic-bundle-op non-propagating-operation) ())
(defclass monolithic-concatenate-source-op
(basic-concatenate-source-op monolithic-bundle-op non-propagating-operation) ()
(:documentation "Operation to concatenate all sources in a system and its dependencies
into a single file"))
(defclass monolithic-load-concatenated-source-op (basic-load-concatenated-source-op)
((selfward-operation :initform 'monolithic-concatenate-source-op :allocation :class)))
((selfward-operation :initform 'monolithic-concatenate-source-op :allocation :class))
(:documentation "Operation to load the result of monolithic-concatenate-source-op as source"))
(defclass monolithic-compile-concatenated-source-op (basic-compile-concatenated-source-op)
((selfward-operation :initform 'monolithic-concatenate-source-op :allocation :class)))
(defclass monolithic-load-compiled-concatenated-source-op (basic-load-compiled-concatenated-source-op)
((selfward-operation :initform 'monolithic-compile-concatenated-source-op :allocation :class)))
((selfward-operation :initform 'monolithic-concatenate-source-op :allocation :class))
(:documentation "Operation to compile the result of monolithic-concatenate-source-op"))
(defclass monolithic-load-compiled-concatenated-source-op
(basic-load-compiled-concatenated-source-op)
((selfward-operation :initform 'monolithic-compile-concatenated-source-op :allocation :class))
(:documentation "Operation to load the result of monolithic-compile-concatenated-source-op"))
(defmethod input-files ((operation basic-concatenate-source-op) (s system))
(loop :with encoding = (or (component-encoding s) *default-encoding*)
......
......@@ -4251,16 +4251,18 @@ by a @code{;} (semicolon) on other platforms (mainly, Windows).
The magic empty entry,
if it comes in what would otherwise be the first entry in a pair,
indicates the splicing of inherited configuration.
indicates the splicing of inherited configuration;
the next entry (if any) then starts a new pair.
If the second entry in a pair is empty,
it indicates that the directory in the first entry is to be left untranslated
(which has the same effect as if the directory had been repeated).
For example, @code{"/foo:/bar::/baz:"} means that
things under directory @file{/foo/}
are translated to be under @file{/bar/},
then include the inherited configuration,
then specify that things under directory @file{/baz/} are not translated.
For example, @code{"/foo:/bar::/baz:"} means:
specify that outputs for things under directory @file{/foo/}
are translated to be under @file{/bar/};
then include the inherited configuration;
then specify that outputs for things under directory @file{/baz/} are not translated.
@node Semantics of Output Translations, Output Caching Results, Output Shell-friendly syntax for configuration, Controlling where ASDF saves compiled files
@section Semantics of Output Translations
......
......@@ -137,7 +137,8 @@
</p><p>
ASDF is also not a tool to build or run Common Lisp software from the Unix command-line.
For that, you want <a href="http://cliki.net/cl-launch">cl-launch</a>,
or perhaps <a href="http://www.xach.com/lisp/buildapp/">buildapp</a>.
<a href="http://www.xach.com/lisp/buildapp/">buildapp</a>, or
<a href="https://github.com/roswell/roswell">roswell</a>.
</p><p>
If you're unsatisfied with ASDF,
beside helping with our
......@@ -160,7 +161,7 @@
</li>
<li>Drew McDermott's
<a href="http://cs-www.cs.yale.edu/homes/dvm/"><tt>YTools</tt></a>
(the polar opposite, trying to maintain coherence
(the polar opposite of XCVB, trying to maintain coherence
of the current Lisp image at a fine grain).
</li>
<li>Dmitriy Ivanov's
......@@ -179,12 +180,17 @@
<li>Peter von Etter's
<a href="http://www.cliki.net/faslpath"><tt>faslpath</tt></a>
(a much simpler system establishing a mapping between packages and files,
abandoned but see <tt>asdf-package-system</tt> and <tt>quick-build</tt> above).
abandoned but see <tt>asdf-package-system</tt> and <tt>quick-build</tt> above),
</li>
<li>Alexander Kahl's
<a href="http://www.cliki.net/evol"><tt>evol</tt></a>
(a reimplementation in Lisp of the GNU autotools stack, abandoned),
</li>
<li>Google's
<a href="https://github.com/qitab/bazelisp"><tt>bazelisp</tt></a>
(building Lisp applications deterministically with
<a href="https://bazel.io/">Bazel</a>).
</li>
</ul>
There are probably more.
However, none of these systems seems to ever have had the traction of ASDF,
......@@ -448,7 +454,8 @@ Corman Common Lisp <admin@cormanlisp.com>
<p>
While bug fixes are useful, they are not usually as valuable as test cases:
small easy fixes will be obvious from the test case,
and large fixes written by someone who isn't a maintainer or working tightly with one
and large fixes written by someone who isn't
either a maintainer or working tightly with one
will probably not be correct and not fit the codebase:
any modification at one point is likely to have repercussions
at other unobvious places in the codebase,
......@@ -582,7 +589,7 @@ Corman Common Lisp <admin@cormanlisp.com>
<a class="nav" href="http://common-lisp.net/" title="Common-Lisp.net"> <img src="http://common-lisp.net/project/cl-containers/shared/buttons/lisp-lizard.png" width="80" height="15" title="Common-Lisp.net" alt="Common-Lisp.net button" /></a>
<p><span class="copyright"Copyright &copy; 2001-2016 Daniel Barlow and contributors</span></p>
<p>ASDF has an <a href="http://www.opensource.org/licenses/mit-license.php">MIT style</a> license</p>
<div id="timestamp">Last updated 2016-08-27</div>
<div id="timestamp">Last updated 2016-09-19</div>
</div>
</body>
</html>
......@@ -51,42 +51,57 @@
(with-upgradability ()
(defgeneric* (find-component) (base path &key registered)
(:documentation "Find a component by resolving the PATH starting from BASE parent"))
(defgeneric resolve-dependency-combination (component combinator arguments))
(:documentation "Find a component by resolving the PATH starting from BASE parent.
If REGISTERED is true, only search currently registered systems."))
(defgeneric resolve-dependency-combination (component combinator arguments)
(:documentation "Return a component satisfying the dependency specification (COMBINATOR . ARGUMENTS)
in the context of COMPONENT"))
;; Methods for find-component
;; If the base component is a string, resolve it as a system, then if not nil follow the path.
(defmethod find-component ((base string) path &key registered)
(if-let ((s (if registered
(registered-system base)
(find-system base nil))))
(find-component s path :registered registered)))
;; If the base component is a symbol, coerce it to a name if not nil, and resolve that.
;; If nil, use the path as base if not nil, or else return nil.
(defmethod find-component ((base symbol) path &key registered)
(cond
(base (find-component (coerce-name base) path :registered registered))
(path (find-component path nil :registered registered))
(t nil)))
;; If the base component is a cons cell, resolve its car, and add its cdr to the path.
(defmethod find-component ((base cons) path &key registered)
(find-component (car base) (cons (cdr base) path) :registered registered))
;; If the base component is a parent-component and the path a string, find the named child.
(defmethod find-component ((parent parent-component) (name string) &key registered)
(declare (ignorable registered))
(compute-children-by-name parent :only-if-needed-p t)
(values (gethash name (component-children-by-name parent))))
;; If the path is a symbol, coerce it to a name if non-nil, or else just return the base.
(defmethod find-component (base (name symbol) &key registered)
(if name
(find-component base (coerce-name name) :registered registered)
base))
;; If the path is a cons, first resolve its car as path, then its cdr.
(defmethod find-component ((c component) (name cons) &key registered)
(find-component (find-component c (car name) :registered registered)
(cdr name) :registered registered))
;; If the path is a component, return it, disregarding the base.
(defmethod find-component ((base t) (actual component) &key registered)
(declare (ignorable registered))
actual)
;; Resolve dependency NAME in the context of a COMPONENT, with given optional VERSION constraint.
;; This (private) function is used below by RESOLVE-DEPENDENCY-SPEC and by the :VERSION spec.
(defun resolve-dependency-name (component name &optional version)
(loop
(restart-case
......@@ -117,13 +132,16 @@
(unset-asdf-cache-entry `(find-system ,name))
(unset-asdf-cache-entry `(locate-system ,name))))))))
;; Resolve dependency specification DEP-SPEC in the context of COMPONENT.
;; This is notably used by MAP-DIRECT-DEPENDENCIES to process the results of COMPONENT-DEPENDS-ON
;; and by PARSE-DEFSYSTEM to process DEFSYSTEM-DEPENDS-ON.
(defun resolve-dependency-spec (component dep-spec)
(let ((component (find-component () component)))
(if</