Commit 2b35d7c9 authored by Robert Goldman's avatar Robert Goldman
Browse files

Merge branch 'plan' into 'master'

Add support for proper phase separation

See merge request !37
parents 5eca3749 65d16a93
......@@ -48,6 +48,7 @@ lib/
test/try-reloading-dependency.asd
test/fileMissing.lisp
test/hello-world-example
test/test-include.asd
build-stamp
......
......@@ -80,13 +80,13 @@ XCL ?= xcl
header_lisp := header.lisp
driver_lisp := uiop/package.lisp uiop/common-lisp.lisp uiop/utility.lisp uiop/version.lisp uiop/os.lisp uiop/pathname.lisp uiop/filesystem.lisp uiop/stream.lisp uiop/image.lisp uiop/lisp-build.lisp uiop/launch-program.lisp uiop/run-program.lisp uiop/configuration.lisp uiop/backward-driver.lisp uiop/driver.lisp
defsystem_lisp := upgrade.lisp cache.lisp component.lisp system.lisp find-system.lisp find-component.lisp operation.lisp action.lisp lisp-action.lisp plan.lisp operate.lisp parse-defsystem.lisp bundle.lisp concatenate-source.lisp output-translations.lisp source-registry.lisp package-inferred-system.lisp backward-interface.lisp backward-internals.lisp interface.lisp user.lisp footer.lisp
defsystem_lisp := upgrade.lisp session.lisp component.lisp operation.lisp system.lisp system-registry.lisp action.lisp lisp-action.lisp find-component.lisp forcing.lisp plan.lisp operate.lisp find-system.lisp parse-defsystem.lisp bundle.lisp concatenate-source.lisp package-inferred-system.lisp output-translations.lisp source-registry.lisp backward-internals.lisp backward-interface.lisp interface.lisp user.lisp footer.lisp
all_lisp := $(header_lisp) $(driver_lisp) $(defsystem_lisp)
print-% : ; @echo $* = $($*)
# Making ASDF itself should be our first, default, target:
build/asdf.lisp: show-version $(all_lisp)
build/asdf.lisp: $(all_lisp)
mkdir -p build
rm -f $@
cat $(all_lisp) > $@
......
* Decree that versions older than 2 years are not supported;
yet, keep supporting an upgrade from whatever vendors provide
— so push them to provide recent stuff.
yet, keep supporting an upgrade from whatever vendors provide
— so push them to provide recent stuff.
** 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
......@@ -17,7 +17,13 @@
** 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?)
* Testing support
** Replace test-op with run-test-op and test-report-op ?
* Implement a style-checker, that will issue STYLE-WARNINGs
when you don't follow all the recommended guidelines.
* Moving toward cross-compilation (ASDF 3.4? 4?)
This would allow to get most of the benefits of XCVB
(reproducibility, scalability, applicability to mobile platforms, etc.),
except without the backward incompatibility of XCVB.
......@@ -112,14 +118,14 @@
make t l=cmucl t=test-encodings.script
which was a different PCL bug from the above (without same workaround)
but possibly also triggered by the non-standard declaim.
*** `#5(1 ,@`(2 3)))` returns #(1 2 3),
rather than #(1 2 3 2 3 2 3 2 3) or even better #(1 2 3 3 3).
*** `#5(1 ,@\`(2 3)))` returns `#(1 2 3)`,
rather than `#(1 2 3 2 3 2 3 2 3)` or even better `#(1 2 3 3 3)`.
*** It purports to support Unicode, but it has only 16-bit characters.
Note that (subtypep 'character 'base-char) says T -- everything is a base char(!)
** SCL has bugs:
*** it doesn't like run-program from a modified directory?
*** it somehow pushes :non-base-chars-exist-p even though +non-base-chars-exist-p+ is NIL???
*** it somehow pushes `:non-base-chars-exist-p` even though `+non-base-chars-exist-p+` is `NIL`???
** XCL has bad bugs:
*** make-pathname doesn't handle :type nil properly and
......@@ -140,6 +146,7 @@
(make-pathname :name "foo" :type :unspecific) ==> #P"foo."
If bug is ever fixed, upgrade *unspecific-pathname-type* in uiop/pathname.
*** XCL doesn't properly process files the name of which contains a *
*** XCL fails to recognize that specialized method parameters are implicitly ignorable.
** GCL is almost working again; but implementation bugs remain.
See Francois-Rene Rideau's messages on gcl-devel starting November 2013.
......@@ -154,33 +161,33 @@
INTERNAL-SIMPLE-ERROR: The package named ASDF/INTERFACE, does not exist
*** Another GCL compiler bug:
when I changed the definition of getcwd from
(let ((*default-pathname-defaults* #p"")) (truename #p"")) to
(let ((*default-pathname-defaults* *nil-pathname*)) (truename *nil-pathname*))
`(let ((*default-pathname-defaults* #p"")) (truename #p""))` to
`(let ((*default-pathname-defaults* *nil-pathname*)) (truename *nil-pathname*))`
to guard against e.g. a logical-pathname context while loading asdf
and parsing #p"", calls to getcwd result in a segfault.
and parsing `#p""`, calls to `getcwd` result in a segfault.
*** An another bug: gcl refuses dynamic-extent declaration on functions.
uiop/stream.lisp: #-gcl (declare (dynamic-extent ,@(when
before `(#',beforef)) ,@(when after `(#',afterf))))
*** (typep p 'logical-pathname) should be T if p has a logical-pathname host.
*** apropos is case-sensitive and returns a same symbol many times
```uiop/stream.lisp: #-gcl (declare (dynamic-extent ,@(when
before `(#',beforef)) ,@(when after `(#',afterf))))```
*** `(typep p 'logical-pathname)` should be T if p has a logical-pathname host.
*** `apropos` is case-sensitive and returns a same symbol many times
(presumably once per package where it is present,
instead of just once for its home package)
*** compile-file fails to return proper secondary values in case of non-style WARNING.
*** (pathname-directory #p"foo/") is incorrectly ("foo") instead of (:RELATIVE "foo")
*** `compile-file` fails to return proper secondary values in case of non-style `WARNING`.
*** `(pathname-directory #p"foo/")` is incorrectly `("foo")` instead of `(:RELATIVE "foo")`
*** Do whatever it takes to pass the asdf tests, add the above?
*** Trying to uiop:slurp-stream-forms from a stream with #+(or) :foo
(or read-file-forms from an file with same) results in an error,
rather than nil. This is probably a bug in #+ processing.
*** Trying to `uiop:slurp-stream-forms` from a stream with `#+(or) :foo`
(or `read-file-forms` from an file with same) results in an error,
rather than `nil`. This is probably a bug in `#+` processing.
Unhappily, debian creates such a file in
/etc/common-lisp/asdf-output-translations.conf.d/01-common-lisp-controller.conf
`/etc/common-lisp/asdf-output-translations.conf.d/01-common-lisp-controller.conf`
*** Tests that try to catch an error fail (but catching a warning succeeds),
which suggests brokenness in handler-bind and/or error.
*** COMPILE-FILE* fails due to handler-bind error in
with-muffled-compiler-conditions or so.
*** `#5(1 ,@`(2 3)))` returns #(1 2 3),
rather than #(1 2 3 2 3 2 3 2 3) or even better #(1 2 3 3 3).
*** (DIRECTORY #p"*.*") fails to match files with pathname type NIL.
*** GCL doesn't properly process files the name of which contains a *
*** `COMPILE-FILE*` fails due to handler-bind error in
`with-muffled-compiler-conditions` or so.
*** `#5(1 ,@`(2 3)))` returns `#(1 2 3)`,
rather than `#(1 2 3 2 3 2 3 2 3)` or even better `#(1 2 3 3 3)`.
*** `(DIRECTORY #p"*.*")` fails to match files with pathname-type `NIL`.
*** GCL doesn't properly process files the name of which contains a `*`
** ABCL has a few bugs.
*** ABCL fails the timestamp propagation test.
......@@ -243,12 +250,6 @@
** Real solution: defer parsing and evaluation of defsystem forms?
Or simply detect circularity and issue an appropriate error?
* Implement proper incrementality for defsystem-depends-on.
** For proper incremental redefinitions, systems probably need to
depend-on (load-asd-op . primary-system) which itself will
depend-on all the load-op of defsystem-depends-on in that file.
https://bugs.launchpad.net/asdf/+bug/1500578
* Include some ABL test for stassats's (now obsolete?) thing:
(asdf:enable-asdf-binary-locations-compatibility
:centralize-lisp-binaries t :default-toplevel-directory *fasl-dir*)
......@@ -382,6 +383,20 @@ It looks like SWANK can be fixed soon, though, so we'll see.
version
* ASDF4: search for this tag, rename things (incompatibly, thus) and cleanup code.
** Migrate from component-depends-on to action-depends-on
*** I contend a future version of ASDF will replace
`(component-depends-on operation component)`
with `(action-depends-on plan operation component)`.
This allows for different normalization strategies for dependencies
(including strategies that avoid resolving things to NIL),
a reified context for featurep checks, etc.
*** Easy but long backward-compatible transition:
**** get all users to use the new gf and keep extending both new and old gf,
meanwhile the new gf has an around method that actually calls the old gf
except in testing mode and/or if we can check that they're using the new convention
**** when everyone has migrated, remove the old mode and the short-circuit.
*** However, we cannot deprecate component-depends-on yet — not until we have
some transition in place to a better interface.
* Documentation
** See message from 2014-01-27 05:26:44 GMT for stuff to document.
......@@ -417,22 +432,6 @@ It looks like SWANK can be fixed soon, though, so we'll see.
*** There again, a check that a forward-package is not backward
would be very nice.
* Migrate from component-depends-on to action-depends-on
** I contend a future version of ASDF will replace
(component-depends-on operation component)
with (action-depends-on plan operation component).
This allows for different normalization strategies for dependencies
(including strategies that avoid resolving things to NIL),
a reified context for featurep checks, etc.
** Easy but long backward-compatible transition:
*** get all users to use the new gf and keep extending both new and old gf,
meanwhile the new gf has an around method that actually calls the old gf
except in testing mode and/or if we can check that they're using the new convention
*** when everyone has migrated, remove the old mode and the short-circuit.
** However, we cannot deprecate component-depends-on yet — not until we have
some transition in place to a better interface.
* Faster source-registry:
** In addition and/or as a substitute to the .cl-source-registry.cache,
that is meant to be semi-automatically managed, there could be
......@@ -457,10 +456,173 @@ It looks like SWANK can be fixed soon, though, so we'll see.
* Properly deprecate all that needs to go
** Get lisa, readable, bourbaki to NOT include ASDF 1 anymore in their sources.
** Identify all the things in ASDF that we want to deprecate, and make
sure we deprecate them all in 3.2.
sure we deprecate them all in 3.4.
** Implement support for deprecating old packages,
by having all functions and macros under the old package name be
proxies to those in the new package name?
(Exception: special variables can't be proxies, have to be imported.)
** Eradicate Quicklisp systems that depend on asdf-driver or
asdf-package-system, make them depend on uiop and asdf3.1 instead.
* Fix plan
** Goal: Implement proper incrementality for defsystem-depends-on.
Fix the bug wherein ASDF fails to properly handle incrementality for `defsystem-depends-on`.
https://bugs.launchpad.net/asdf/+bug/1500578
Some discussion about ASDF at
http://ccl.clozure.com/irc-logs/lisp/lisp-2016-10.txt
** DONE Items
*** Add `DEFINE-OP` for loading system definitions.
*** A `DEFINE-OP` will depend on other `DEFINE-OP`s
*** A `DEFINE-OP` depends on all `LOAD-OP` in the file.
Whether via defsystem-depends-on or manual `LOAD-OP`s.
*** Store timestamps in `DEFINE-OP` entries, not `*DEFINED-SYSTEMS*`.
*** In find-system, add condition that all dependencies are up-to-date.
*** This necessitates another layer of visit states,
that do not plan, just check planning...
*** `LOAD-ASD` calls `PERFORM DEFINE-OP` (not the other way around)
*** Systems probably need depend on `(DEFINE-OP . PRIMARY-SYSTEM)`
*** These dynamically-discovered dependencies are stored in a slot of `SYSTEM`.
*** Have a special kind of definition-depends-on dependency.
Before we reuse a node from a previous session,
we must make sure it is still properly defined.
This matters because we do reuse (at least *some* nodes, e.g. system nodes)
from previous sessions, and the control structure may have changed
(i.e. the system hasn't been redefined, but one of its defsystem-depends-on
dependencies has changed).
*** Handle incomplete definitions properly
Don't just let the incompletely parsed system be registered
in a false positive success as if it were an empty system.
Solution: It is registered, but considered out-of-date,
so next attempt to use it will cause a refresh attempt.
https://bugs.launchpad.net/asdf/+bug/1515372
*** Handle nested calls to `OPERATE`
We must accept that ASDF isn't really plan-then-perform,
as the ASDF1 model claimed to be.
It's an arbitrary nesting of plan-and-perform, like a parenthesization
with plan (steps) as left parenthesis and perform (steps) as right parenthesis,
and with operate being a maximal balanced span of plan and perform steps.
*** What goes in a shared dynamic `*SESSION*`, what in a private lexical `PLAN`?
Memoization CACHE of various functions, Status of VISITED-NODES, FORCING parameters.
The session will contain not just the current `*CACHE*`, but also
all or most of the graph traversal, thus the `:force` options, etc.
The `*PLAN*` may or may not contain some work queueing.
But even, e.g. a table of "nodes still directly blocking us"
is shared at the shared traversal level.
*** It is an error for a nested `OPERATE` to contradict session flags.
This raises the question of `:force` and `:force-not` flags.
An actual operate cannot contradict them and cause things to be performed
with a wrong subset of dependencies loaded.
Yet, `REQUIRED-COMPONENTS` (that does cause anything to be performed —
except via nested `OPERATE` from `defsystem-depends-on`)
must be able to skip some dependencies
(though maybe only _in addition_ to the global ones).
*** What timestamp for `forced` and `forced-not` actions?
If an action is forced-not, it should be returned with an action stamp from this cache,
and not with `nil` as is currently wrongly done
(unless of course the cache entry is missing,
at which point `nil` is the correct answer).
Conversely, a force means the stamp should be `t`
(indicating it needs to be done in the future)
(that part asdf gets right).
*** Handle planning things that are now done but were done in a previous phase of the build,
so dependency on them should trigger the build.
*** Protocol to not re-perform an action twice
In PERFORM-PLAN, check that an action wasn't already DONE-P due to
being needed in a previous phase of recursively calling OPERATE,
before to PERFORM it.
To correctly propagate timestamps in across nested calls,
the graph traversal and timestamp propagation is shared at the session level
between all nested calls to `OPERATE`.
During a session and across phases, every action has a status made of
a stamp and three bits: KEEP-P, DONE-P, NEED-P.
The stamp also survives across sessions, in `COMPONENT-OPERATION-TIMES`.
*** Detect circularities across nested calls to `OPERATE`
This means the circularity detection data is part of the session.
Notably, the visiting list and set.
The top of the list can also serve to record the dependencies from `OPERATE` to `DEPEND-OP`.
*** In UIOP, RECORD-DEPENDENCY must not cross to an upper plan and/or it should
record the dependency in said upper plan (that matters because
parallel plans doing extra checking, and this is a problem
whereby some links to extra actions are left unresolved).
Maybe in the future, record the dependency in the session, not in a plan.
** TODO items
*** find-system should probably cause a dependency on define-op, especially inside another define-op
*** Is it worth it trying to optimize away a dependency on a define-op
when an action already depends on another operation that "obviously" depends on that define-op?
*** Document DEFINE-OP and the design in asdf.texinfo and/or in some article.
** Future developments
*** Grovel all .asd files in Quicklisp and collect all violations of declarativeness,
where declarativeness is having only defsystem forms. Specially classify in-package,
maybe also defpackage. Then we can assess the impact of requiring declarativeness.
*** Also grovel Quicklisp for all extensions to ASDF:
see if there are new methods on perform, input-files, output-files, operate, etc.
*** To allow defsystem-depends-on to another secondary system within the
same file, I can imagine some system to dynamically create a separate action
(DEFINE-OP foo/x) for each form defsystem foo/x, and have it depend on
all the preceding actions operated in the .asd file.
Plus a last action for dangling load-system or operate statements?
Or one action for every operate statement?
There would be no action of the entire load-asd, but a separate mechanism
to detect circularity?
What about dangling statements? They would be a bit like xcvb weakly-ordered
run-time dependencies that CAN have circularities? Ouch. Really ugly.
Each statement would need its own action? Ouch.
*** Have load-asd clear any invalidated previous secondary system
before loading, which supposes remembering what these systems are.
Then, you're not allowed to forward-reference a secondary system that
hasn't been defined yet while you're loading the .asd, whereas you
can load the asd if you aren't loading it yet.
*** Maybe split DEFINE-OP into PREPARE-DEFINE-OP and DEFINE-OP, so that
secondary systems can be properly loaded?
*** Add mapping from files to action that creates it and/or uses it?
Then we can detect conflict between multiple actions creating one file.
Forbid direct use of files not listed as inputs? What about transitive inputs?
Build in a container that has only the proper files...
*** What data structure for scheduling planned actions?
A doubly-linked to remove entire chunks of the plan after a sub-operate?
That won't do, because later-discovered defsystem dependency can refer to
systems that were planned but not performed, so there need be no contiguity
in the chunks that are performed by subcalls to operate.
Actually, if we otherwise forbid reference to another system
from non-system components, then we could move things with system granularity,
which is one thing; but we still need a general mechanism at the system level.
So, whether it's an explicit queue or an implicit traversal of the dependency graph,
we must check whether an action has already been done before we try to perform it.
And an implicit traversal has the advantage that you can avoid entire subtrees
when you find that the current node has already been performed during
a previous phase of the plan.
In conclusion: "just" traverse the graph at the last minute, and
perform things serially, and/or if you want some parallelism,
build a queue dynamically at the last minute for the "now" jobs
while keeping most of the plan as graph structures.
*** Merging in parts of POIU?
ASDF internals are nothing to be proud of:
ASDF1 was optimized for "smallest code that kind of works in the usual case",
and ASDF3 was optimized for "smallest code that fixes ASDF1 in the general case
while mostly maintaining backward compatibility".
Because of its optimization constraint, ASDF1 was using and abusing lists a lot,
rather than defining nice data structures.
ASDF3 uses somewhat more structured data, with a few more classes, and
algorithms that are O(n) instead of O(n**3) in simple cases and
exponential in carefully crafted examples;
yet it has shunned any definition of more advanced or general data structures.
By contrast, POIU has a dequeue to represent queued compilation jobs, and
a general graph representation for the action graph
(though the original POIU was also O(n**3) because it lacked PREPARE-OP).
I could import the POIU queue and graph representations into ASDF, and
that would add about 100 lines of code to UIOP for the queue, and
200 lines to ASDF for the graph, maybe a bit more if the code is
generalized, commented and largely put in UIOP.
Then, there's the support for actual forking and using forks,
that would be about 400 lines added to UIOP, and
the using it in ASDF to consume the plan, which would be under 200 lines.
But those parts are probably better left out of ASDF itself.
That said, it all was a lot when ASDF was < 1000 lines of code,
but isn't all that much now that it is > 12000 lines of code.
......@@ -3,24 +3,26 @@
(uiop/package:define-package :asdf/action
(:nicknames :asdf-action)
(:recycle :asdf/action :asdf)
(:use :uiop/common-lisp :uiop :asdf/upgrade
:asdf/component :asdf/system #:asdf/cache :asdf/find-system :asdf/find-component :asdf/operation)
(:recycle :asdf/action :asdf/plan :asdf)
(:use :uiop/common-lisp :uiop :asdf/upgrade :asdf/session :asdf/component :asdf/operation)
(:import-from :asdf/operation #:check-operation-constructor)
#-clisp (:unintern #:required-components #:traverse-action #:traverse-sub-actions)
(:import-from :asdf/component #:%additional-input-files)
(:export
#:action #:define-convenience-action-methods
#:action-description
#:downward-operation #:upward-operation #:sideway-operation #:selfward-operation #:non-propagating-operation
#:action-description #:format-action
#:downward-operation #:upward-operation #:sideway-operation #:selfward-operation
#:non-propagating-operation
#:component-depends-on
#:input-files #:output-files #:output-file #:operation-done-p
#:action-status #:action-stamp #:action-done-p
#:action-operation #:action-component #:make-action
#:component-operation-time #:mark-operation-done #:compute-action-stamp
#:perform #:perform-with-restarts #:retry #:accept
#:action-path #:find-action #:stamp #:done-p
#:action-path #:find-action
#:operation-definition-warning #:operation-definition-error ;; condition
))
#:action-valid-p
#:circular-dependency #:circular-dependency-actions
#:call-while-visiting-action #:while-visiting-action
#:additional-input-files))
(in-package :asdf/action)
(eval-when (#-lispworks :compile-toplevel :load-toplevel :execute) ;; LispWorks issues spurious warning
......@@ -49,9 +51,10 @@ and a class-name or class designates the canonical instance of the designated cl
(with-upgradability ()
(defun action-path (action)
"A readable data structure that identifies the action."
(let ((o (action-operation action))
(c (action-component action)))
(cons (type-of o) (component-find-path c))))
(when action
(let ((o (action-operation action))
(c (action-component action)))
(cons (type-of o) (component-find-path c)))))
(defun find-action (path)
"Reconstitute an action from its action-path"
(destructuring-bind (o . c) path (make-action (make-operation o) (find-component () c)))))
......@@ -109,7 +112,7 @@ and a class-name or class designates the canonical instance of the designated cl
,if-no-component))))))))
;;;; self-description
;;;; Self-description
(with-upgradability ()
(defgeneric action-description (operation component)
(:documentation "returns a phrase that describes performing this operation
......@@ -127,6 +130,42 @@ Use it in FORMAT control strings as ~/asdf-action:format-action/"
(princ (action-description operation component) stream))))
;;;; Detection of circular dependencies
(with-upgradability ()
(defun (action-valid-p) (operation component)
"Is this action valid to include amongst dependencies?"
;; If either the operation or component was resolved to nil, the action is invalid.
;; :if-feature will invalidate actions on components for which the features don't apply.
(and operation component
(if-let (it (component-if-feature component)) (featurep it) t)))
(define-condition circular-dependency (system-definition-error)
((actions :initarg :actions :reader circular-dependency-actions))
(:report (lambda (c s)
(format s (compatfmt "~@<Circular dependency: ~3i~_~S~@:>")
(circular-dependency-actions c)))))
(defun call-while-visiting-action (operation component fun)
"Detect circular dependencies"
(with-asdf-session ()
(with-accessors ((action-set visiting-action-set)
(action-list visiting-action-list)) *asdf-session*
(let ((action (cons operation component)))
(when (gethash action action-set)
(error 'circular-dependency :actions
(member action (reverse action-list) :test 'equal)))
(setf (gethash action action-set) t)
(push action action-list)
(unwind-protect
(funcall fun)
(pop action-list)
(setf (gethash action action-set) nil))))))
;; Syntactic sugar for call-while-visiting-action
(defmacro while-visiting-action ((o c) &body body)
`(call-while-visiting-action ,o ,c #'(lambda () ,@body))))
;;;; Dependencies
(with-upgradability ()
(defgeneric component-depends-on (operation component) ;; ASDF4: rename to component-dependencies
......@@ -269,7 +308,7 @@ The class needs to be updated for ASDF 3.1 and specify appropriate propagation m
don't. In the future this functionality will be removed, and the default will be no propagation."
(uiop/version::notify-deprecated-function
(version-deprecation *asdf-version* :style-warning "3.2")
'backward-compatible-depends-on)
`(backward-compatible-depends-on :for-operation ,o))
`(,@(sideway-operation-depends-on o c)
,@(when (typep c 'parent-component) (downward-operation-depends-on o c))))
......@@ -341,10 +380,24 @@ They may rely on the order of the files to discriminate between inputs.
(assert (length=n-p files 1))
(first files)))
(defgeneric additional-input-files (operation component)
(:documentation "Additional input files for the operation on this
component. These are files that are inferred, rather than
explicitly specified, and these are typically NOT files that
undergo operations directly. Instead, they are files that it is
important for ASDF to know about in order to compute operation times,etc."))
(define-convenience-action-methods additional-input-files (operation component))
(defmethod additional-input-files ((op operation) (comp component))
(cdr (assoc op (%additional-input-files comp))))
;; Memoize input files.
(defmethod input-files :around (operation component)
(do-asdf-cache `(input-files ,operation ,component)
(call-next-method)))
;; get the additional input files, if any
(append (call-next-method)
;; must come after the first, for other code that
;; assumes the first will be the "key" file
(additional-input-files operation component))))
;; By default an action has no input-files.
(defmethod input-files ((o operation) (c component))
......@@ -377,7 +430,8 @@ They may rely on the order of the files to discriminate between inputs.
Updates the action's COMPONENT-OPERATION-TIME to match the COMPUTE-ACTION-STAMP
using the JUST-DONE flag."))
(defgeneric compute-action-stamp (plan operation component &key just-done)
(defgeneric compute-action-stamp (plan- operation component &key just-done)
;; NB: using plan- rather than plan above allows clisp to upgrade from 2.26(!)
(:documentation "Has this action been successfully done already,
and at what known timestamp has it been done at or will it be done at?
* PLAN is a plan object modelling future effects of actions,
......@@ -393,29 +447,17 @@ Returns two values:
* a boolean DONE-P that indicates whether the action has actually been done,
and both its output-files and its in-image side-effects are up to date."))
(defclass action-status ()
((stamp
:initarg :stamp :reader action-stamp
:documentation "STAMP associated with the ACTION if it has been completed already
in some previous image, or T if it needs to be done.")
(done-p
:initarg :done-p :reader action-done-p
:documentation "a boolean, true iff the action was already done (before any planned action)."))
(:documentation "Status of an action"))
(defmethod print-object ((status action-status) stream)
(print-unreadable-object (status stream :type t)
(with-slots (stamp done-p) status
(format stream "~@{~S~^ ~}" :stamp stamp :done-p done-p))))
(defmethod component-operation-time ((o operation) (c component))
(gethash o (component-operation-times c)))
(defmethod (setf component-operation-time) (stamp (o operation) (c component))
(assert stamp () "invalid null stamp for ~A" (action-description o c))
(setf (gethash o (component-operation-times c)) stamp))
(defmethod mark-operation-done ((o operation) (c component))
(setf (component-operation-time o c) (compute-action-stamp nil o c :just-done t))))
(let ((stamp (compute-action-stamp nil o c :just-done t)))
(assert stamp () "Failed to compute a stamp for completed action ~A" (action-description o c))1
(setf (component-operation-time o c) stamp))))
;;;; Perform
......@@ -424,6 +466,8 @@ in some previous image, or T if it needs to be done.")
(:documentation "PERFORM an action, consuming its input-files and building its output-files"))
(define-convenience-action-methods perform (operation component))
(defmethod perform :around ((o operation) (c component))
(while-visiting-action (o c) (call-next-method)))
(defmethod perform :before ((o operation) (c component))
(ensure-all-directories-exist (output-files o c)))
(defmethod perform :after ((o operation) (c component))
......
......@@ -21,7 +21,13 @@
#+asdf3
(defsystem "asdf/driver"
:depends-on ("uiop"))
;; This is the same as "uiop", but used for transclusion in asdf.lisp.
;; Because asdf.asd can't afford to depend on reading uiop.asd
;; (which would cause circularity, since everything depends on reading asdf.asd),
;; we can't "just" :depends-on ("uiop") like we used to do.
:pathname "uiop"
:around-compile call-without-redefinition-warnings ;; we need be the same as uiop
:components #.(getf (read-file-form (subpathname *load-pathname* "uiop/uiop.asd") :at 2) :components))
#+asdf3
(defsystem "asdf/defsystem"
......@@ -40,28 +46,31 @@
:build-operation monolithic-concatenate-source-op
:build-pathname "build/asdf" ;; our target
:around-compile call-without-redefinition-warnings ;; we need be the same as uiop
:depends-on ("asdf/prelude" "uiop")
:depends-on ("asdf/prelude" "asdf/driver")
:encoding :utf-8
:components
((:file "upgrade")
(:file "cache" :depends-on ("upgrade"))
(:file "component" :depends-on ("upgrade"))
(:file "session" :depends-on ("upgrade"))
(:file "component" :depends-on ("session"))
(:file "operation" :depends-on ("session"))
(:file "system" :depends-on ("component"))
(:file "find-system" :depends-on ("system" "cache"))
(:file "find-component" :depends-on ("find-system"))
(:file "operation" :depends-on ("find-system"))
(:file "action" :depends-on ("find-component" "operation"))
(:file "system-registry" :depends-on ("system"))
(:file "action" :depends-on ("session" "system" "operation"))
(:file "lisp-action" :depends-on ("action"))
(:file "plan" :depends-on ("lisp-action"))
(:file "find-component" :depends-on ("component"))
(:file "forcing" :depends-on ("operation" "system-registry"))
(:file "plan" :depends-on ("lisp-action" "find-component" "forcing"))
(:file "operate" :depends-on ("plan"))
(:file "parse-defsystem" :depends-on ("cache" "system" "lisp-action" "operate"))
(:file "bundle" :depends-on ("lisp-action" "operate" "parse-defsystem"))
(:file "concatenate-source" :depends-on ("plan" "parse-defsystem" "bundle"))
(:file "find-system" :depends-on ("system-registry" "operate"))
(:file "parse-defsystem" :depends-on ("system-registry" "lisp-action" "operate"
"find-system"))
(:file "bundle" :depends-on ("lisp-action" "parse-defsystem"))
(:file "concatenate-source" :depends-on ("bundle"))
(:file "package-inferred-system" :depends-on ("parse-defsystem"))
(:file "output-translations" :depends-on ("operate"))
(:file "source-registry" :depends-on ("find-system"))
(:file "package-inferred-system" :depends-on ("system" "find-system" "parse-defsystem"))
(:file "backward-interface" :depends-on ("operate" "output-translations"))
(:file "backward-internals" :depends-on ("find-system" "parse-defsystem"))
(:file "backward-interface" :depends-on ("output-translations"))
(:file "interface" :depends-on
("parse-defsystem" "concatenate-source"
"output-translations" "source-registry" "package-inferred-system"
......@@ -85,4 +94,3 @@
#+asdf3 :builtin-system-p #+asdf3 t
:components ((:module "build" :components ((:file "asdf"))))
:in-order-to (#+asdf3 (prepare-op (monolithic-concatenate-source-op "asdf/defsystem"))))
......@@ -3,9 +3,10 @@
(uiop/package:define-package :asdf/backward-interface
(:recycle :asdf/backward-interface :asdf)
(:use :uiop/common-lisp :uiop :asdf/upgrade
:asdf/component :asdf/system :asdf/find-system :asdf/operation :asdf/action
:asdf/lisp-action :asdf/plan :asdf/operate :asdf/output-translations)
(:use :uiop/common-lisp :uiop :asdf/upgrade :asdf/session
:asdf/component :asdf/system :asdf/system-registry :asdf/operation :asdf/action
:asdf/lisp-action :asdf/plan :asdf/operate
:asdf/find-system :asdf/parse-defsystem :asdf/output-translations :asdf/bundle)
(:export
#:*asdf-verbose*
#:operation-error #:compile-error #:compile-failed #:compile-warned
......@@ -15,13 +16,14 @@
#:operation-on-failure #:operation-on-warnings #:on-failure #:on-warnings
#:component-property
#:run-shell-command
#:system-definition-pathname
#:explain))
#:system-definition-pathname #:system-registered-p #:require-system
#:explain
#+ecl #:make-build))
(in-package :asdf/backward-interface)
;; NB: the warning status of these functions may have to be distinguished later,
;; as some get removed faster than the others in client code.