Lisp HUG Maillist Archive

ASDF Patch for LispWorks

Consider the (silly) system definition below.

FILE S1.ASD

> (in-package #:common-lisp-user)
>
> (defpackage #:s1-system
> 	    (:use #:common-lisp #:asdf))
>
> (in-package #:s1-system)
>
> (defsystem s1
>   :components
>   ((:module "main"
>     :pathname ""
>     :components ((:file "f1")
> 		 )))
>   :perform
>   (load-op :after (op c)
> 	   (print (list :load :after op c))))

Loading this once in LispWorks 5.01 Personal (OS X Mactel) is fine;  
loading twice is unhappy.

>
> CL-USER 1 > (load "/repository/cclan/asdf/asdf")
> ; Loading text file /repository/cclan/asdf/asdf.lisp
> #P"/repository/cclan/asdf/asdf.lisp"
>
> CL-USER 2 > (load "/repository/other/ts-20/lisp/experimental/asdf- 
> problem/s1.asd")
> ; Loading text file /repository/other/ts-20/lisp/experimental/asdf- 
> problem/s1.asd
> #P"/repository/other/ts-20/lisp/experimental/asdf-problem/s1.asd"
>
> CL-USER 3 > (load "/repository/other/ts-20/lisp/experimental/asdf- 
> problem/s1.asd")
> ; Loading text file /repository/other/ts-20/lisp/experimental/asdf- 
> problem/s1.asd
>
> Error: No applicable methods for #<STANDARD-GENERIC-FUNCTION  
> HARLEQUIN-COMMON-LISP:GENERIC-FUNCTION-NAME 2091E0DA> with args (NIL)
>   1 (continue) Call #<STANDARD-GENERIC-FUNCTION HARLEQUIN-COMMON- 
> LISP:GENERIC-FUNCTION-NAME 2091E0DA> again
>   2 Try loading /repository/other/ts-20/lisp/experimental/asdf- 
> problem/s1.asd again.
>   3 Give up loading /repository/other/ts-20/lisp/experimental/asdf- 
> problem/s1.asd.
>   4 Try loading another file instead of /repository/other/ts-20/ 
> lisp/experimental/asdf-problem/s1.asd.
>   5 (abort) Return to level 0.
>   6 Return to top loop level 0.
>
> Type :b for backtrace, :c <option number> to proceed,  or :? for  
> other options
>
> S1-SYSTEM 4 : 1 >

The problem, as I see it, is in parse-component-form. It currently uses

>       (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
> 	   (destructuring-bind (op qual (o c) &body body) v
> 		 (pushnew
> 		  (eval `(defmethod ,n ,qual ((,o ,op) (,c (eql ,ret)))
> 			  ,@body))
> 		  (component-inline-methods ret))))

to update the inline-methods (e.g., perform, explain, etc) of a  
system. Since component-inline-methods is never cleared, it can end  
up with methods that don't exist and (at least on LispWorks), these  
methods can be of the form

#<STANDARD-METHOD NIL (:AFTER) (#<STANDARD-CLASS ASDF:LOAD-OP  
21778B0C> (
      (EQL #<ASDF::SYSTEM-CONNECTION "bind-and-metatilities" 214F08F4>))

I.e., the method name is nil; this then causes LispWorks to complain  
when it tries to remove the method whose name is nil.

I propose the following patch:

1. Add

(defparameter +asdf-methods+
   '(perform explain output-files operation-done-p))

to prevent duplication

2. Replace the code above with:

> ;; remove old methods
>       (loop for name in +asdf-methods+
> 	    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 name) m))
> 		    (component-inline-methods ret)))
>       ;; clear methods, then add the new ones
>       (setf (component-inline-methods ret) nil)
>       (loop for name in +asdf-methods+
> 	   for v = (getf rest (intern name :keyword))
> 	 when v do
> 	   (destructuring-bind (op qual (o c) &body body) v
> 	     (pushnew
> 	      (eval `(defmethod ,name ,qual ((,o ,op) (,c (eql ,ret)))
> 				,@body))
> 	      (component-inline-methods ret))))

Patch attached.

If there is not discussion, I'll commit this in a few days.


Updated at: 2020-12-10 08:46 UTC