A :files clause and a possible change to parse-component-form
Gary King <[email protected]>
| Newsgroups | gmane.lisp.cclan.general |
|---|---|
| Message-ID | <[email protected]> |
Overall, I think ASDF is very nice. There is one thing, however, which
I dislike: the amount of boilerplate code involved in defining a system
with many files when the dependencies are already encoded in the file
ordering. As an example, I'd rather type
(asdf:defsystem :eksl-utilities-base
:version "1.0"
:components ((:files ("package"
"l0-utils"
"anaphoric"
"graham"
"feature-case"
"macros"
"spy"
"timeit"
"utilities"
"string-utilities"
"debugging-utils"
"day-and-time"
"copy"
"clos-mop-utils"
"clos-utils"
"clos-mixins"
"class-defs"
"indentation"
"longest-subsequence"))))
Than
(asdf:defsystem :eksl-utilities-base
:version "1.0"
:components ((:FILE "package")
(:FILE "l0-utils")
(:FILE "anaphoric")
(:FILE "graham")
(:FILE "feature-case")
(:FILE "macros")
(:FILE "spy")
(:FILE "timeit")
(:FILE "utilities")
(:FILE "string-utilities")
(:FILE "debugging-utils")
(:FILE "day-and-time")
(:FILE "copy")
(:FILE "clos-mop-utils")
(:FILE "clos-utils")
(:FILE "clos-mixins")
(:FILE "class-defs")
(:FILE "indentation")
(:FILE "longest-subsequence")))
Though there are probably other ways to do this, the easiest way I
found was to modify parse-component-form to break on the type and then
call a helper method (parse-component-form-aux) that dispatches on that
type. When the type is :files, the method simply calls the helper with
each file; otherwise, parse-component-form-aux does the same work that
parse-component-form does. Note that I'm not sure how this suggested
implementation will play with non-Lisp files.
(defun parse-component-form (parent options)
(destructuring-bind (type datum &rest rest &key
depends-on components in-order-to
&allow-other-keys)
options
(check-component-input type datum depends-on components in-order-to)
(apply #'parse-component-form-aux type datum parent rest)))
;;;
------------------------------------------------------------------------
---
(defmethod parse-component-form-aux ((type (eql :files)) files parent
&rest options
&key &allow-other-keys)
(loop for file in files collect
(apply #'parse-component-form-aux :file file parent options)))
;;;
------------------------------------------------------------------------
---
(defmethod parse-component-form-aux ((type symbol) name parent &rest
options
&key
;; the following list of keywords
is reproduced below in the
;; remove-keys form. important to
keep them in sync
components pathname
default-component-class
perform explain output-files
operation-done-p
depends-on serial in-order-to
;; list ends
&allow-other-keys)
(let* ((other-args (remove-keys
'(components pathname default-component-class
perform explain output-files operation-done-p
depends-on serial in-order-to)
options))
(ret
(or (find-component parent name)
(make-instance (class-for-type parent type)))))
(when (boundp '*serial-depends-on*)
(setf depends-on
(concatenate 'list *serial-depends-on* depends-on)))
(apply #'reinitialize-instance
ret
:name (coerce-name name)
:pathname pathname
:parent parent
other-args)
(when (typep ret 'module)
(setf (module-default-component-class ret)
(or default-component-class
(and (typep parent 'module)
(module-default-component-class parent))))
(let ((*serial-depends-on* nil))
(setf (module-components ret)
(loop for c-form in components
for c = (parse-component-form ret c-form)
append (if (consp c) c (list c))
if serial
do (push (component-name c) *serial-depends-on*)))))
(setf (slot-value ret 'in-order-to)
(union-of-dependencies
in-order-to
`((compile-op (compile-op ,@depends-on))
(load-op (load-op ,@depends-on))))
(slot-value ret 'do-first) `((compile-op (load-op
,@depends-on))))
(loop for (n v) in `((perform ,perform) (explain ,explain)
(output-files ,output-files)
(operation-done-p ,operation-done-p))
do (map 'nil
;; this is inefficient as most of the stored
;; methods will not be for this particular gf n
;; But this is hardly performance-critical
(lambda (m) (remove-method (symbol-function n) m))
(component-inline-methods ret))
when v
do (destructuring-bind (op qual (o c) &body body) v
(pushnew
(eval `(defmethod ,n ,qual ((,o ,op) (,c (eql ,ret)))
,@body))
(component-inline-methods ret))))
ret))
--
Gary Warren King, Lab Manager
EKSL East, University of Massachusetts * 413 577 0176
In the end, compassion has to be the greatest family value
-- Billy Bragg