[PATCH] Proposal: implement feature-dependent-op

Richard M Kreuter <[email protected]>
Newsgroups gmane.lisp.cclan.general
Message-ID <[email protected]>
Hello,

asdf.texinfo describes an abstract class, FEATURE-DEPENDENT-OP, which
asdf.lisp doesn't implement.  I've attached a patch and some tests,
but am more looking for feedback than asking that these changes go in
at this time.

With this functionality, a system that one might write today like
this:

(defsystem my-system
  :components (#+sbcl
               (:file "file1")
               #+clisp
               (:file "file2")
               #-(or sbcl clisp)
               (:file "file3")
               ...))

would (and should) instead be written like this:

(defsystem my-system
  :components ((:file "file1" :features :sbcl)
               (:file "file2" :features :clisp)
               (:file "file3" :features (:not (:or :sbcl :clisp)))
               ...))

This way, systems will contain all the files actually present on the
filesystem no matter what Lisp the .asd file is read into; operations
that are meant to be carried out on all the files in the system can
work correctly (e.g., making release tarballs or formatting a system
for online display or for printing), while compile-op, load-op, and
other operations can still be contingent on the host Lisp's features.
The current practice of using read-time conditionals makes many
conceivable operations essentially impossible to implement, because
read-time conditionalization makes system composition
feature-dependent (which works out to implementation-dependent in the
common case).  In effect, all implementable asdf operations are
feature-dependent at present.

Limitations: I haven't yet figured out how to make inter-system
dependencies feature-dependent.  Doing so looks as though it will be
tricky, and the benefit (to allow *features* to influence whether one
system depends on another at operation-time) might not be worth the
additional hassle for the user.  I'd like to hear people's thoughts
about this.

Finally, for downward compatibility, I've added a feature,
:ASDF-HAS-FEATURE-DEPENDENT-OP, so that .asd files can be written as
follows, if the author wishes to support old versions of asdf.lisp:

(defsystem my-system
  :components (#+(or (not asdf-has-feature-dependent-op) sbcl)
               (:file "sbcl" #+asdf-has-feature-dependent-op :features
                             #+asdf-has-feature-dependent-op :sbcl)
               #+(or (not asdf-has-feature-dependent-op) clisp)
               (:file "clisp" #+asdf-has-feature-dependent-op :features
                              #+asdf-has-feature-dependent-op :clisp)
               #-(or (not asdf-has-feature-dependent-op) (or sbcl clisp))
               (:file "clisp" #+asdf-has-feature-dependent-op :features
                              #+asdf-has-feature-dependent-op
                              (:not (:or :sbcl :clisp))))

Systems written in this (admittedly ugly) way will continue to
compile-op and load-op correctly on old versions of asdf.lisp, but
will not support feature-independent operations (that's the "downward"
bit).  Users who want feature-independent operations will have to
upgrade their asdf.lisp, but won't have to change .asd files written
this way.  Of course, system authors can just require their users to
get a newer asdf.lisp, too, but that's between system authors and
their users.  In the long term, putting the feature expressions into
the defsystem form should be the preferred thing.

Of course, all the details of the patch are negotiable, but I think
some functionality like this ought to get into asdf.

Any thoughts?

Thanks,
RmK

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

_______________________________________________
cclan-list mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/cclan-list
asdf-f-d-o.diff (text/x-patch, 3.3 KB)
Index: asdf.lisp
===================================================================
RCS file: /cvsroot/cclan/asdf/asdf.lisp,v
retrieving revision 1.102
diff -u -r1.102 asdf.lisp
--- asdf.lisp	7 Nov 2006 10:27:13 -0000	1.102
+++ asdf.lisp	21 Jan 2007 20:24:16 -0000
@@ -44,6 +44,7 @@
 	   
 	   #:compile-op #:load-op #:load-source-op #:test-system-version
 	   #:test-op
+	   #:feature-dependent-op
 	   #:operation			; operations
 	   #:feature			; sort-of operation
 	   #:version			; metaphorically sort-of an operation
@@ -202,7 +203,10 @@
    ;; XXX we should provide some atomic interface for updating the
    ;; component properties
    (properties :accessor component-properties :initarg :properties
-	       :initform nil)))
+	       :initform nil)
+   ;; An expression that must be satisifed as by featurep below in
+   ;; order for an operation to be performed on a component.
+   (features :initarg :features :accessor component-features)))
 
 ;;;; methods: conditions
 
@@ -622,6 +626,27 @@
               (> (apply #'min (mapcar #'file-write-date out-files))
                  (apply #'max (mapcar #'fwd-or-return-t in-files)))))))))
 
+;;; feature-dependent-op
+(defclass feature-dependent-op (operation)
+  ())
+
+;; feature-dependent-op needs a run-time implementation of this.
+(defun featurep (feature-expression)
+  (when feature-expression
+    (etypecase feature-expression
+      (symbol
+       (member feature-expression *features*))
+      (cons
+       (let ((bool (car feature-expression)))
+         (ecase bool
+           (:and
+            (every #'featurep (rest feature-expression)))
+           (:or
+            (some #'featurep (rest feature-expression)))
+           (:not
+            (not (featurep (cadr feature-expression))))))))))
+
+
 ;;; So you look at this code and think "why isn't it a bunch of
 ;;; methods".  And the answer is, because standard method combination
 ;;; runs :before methods most->least-specific, which is back to front
@@ -658,6 +683,13 @@
 					(do-one-dep op (second d) (third d))))
                               (t
                                (appendf forced (do-one-dep op d nil)))))))))
+      ;; If the op is an f-d-o and the component's feature conditions
+      ;; obtain, return the empty list so that the component's
+      ;; dependencies get skipped, too.
+      (when (and (typep operation 'feature-dependent-op)
+                 (slot-boundp c 'features)
+                 (not (featurep (component-features c))))
+        (return-from traverse ()))
       (aif (component-visited-p operation c)
 	   (return-from traverse
 	     (if (cdr it) (list (cons 'pruned-op c)) nil)))
@@ -722,7 +754,7 @@
 
 ;;; compile-op
 
-(defclass compile-op (operation)
+(defclass compile-op (feature-dependent-op)
   ((proclamations :initarg :proclamations :accessor compile-op-proclamations :initform nil)
    (on-warnings :initarg :on-warnings :accessor operation-on-warnings
 		:initform *compile-file-warnings-behaviour*)
@@ -776,7 +808,7 @@
 
 ;;; load-op
 
-(defclass basic-load-op (operation) ())
+(defclass basic-load-op (feature-dependent-op) ())
 
 (defclass load-op (basic-load-op) ())
 
@@ -1173,6 +1205,7 @@
 
 
 (pushnew :asdf *features*)
+(pushnew :asdf-has-feature-dependent-op *features*)
 
 #+sbcl
 (eval-when (:compile-toplevel :load-toplevel :execute)
file5.lisp (application/octet-stream, 46 B) - not displayed
test5.asd (application/octet-stream, 439 B) - not displayed
test5.script (application/octet-stream, 1.3 KB) - not displayed
test6.asd (application/octet-stream, 696 B) - not displayed
test6.script (application/octet-stream, 1.3 KB) - not displayed
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.