Define a Simple Echo-Op

zacque technical+asdfdevel at zacque.tk
Wed Apr 27 07:21:52 UTC 2022


Hi phoebe,

Thanks for your thoughtful reply!

> A few things.
>
> 1. ECHO-OP should not be selfward. SELFWARD-OPERATION is for (OPERATION COMPONENT) pairs which depend on
> (DIFFERENT-OPERATION COMPONENT) for the same COMPONENT. For example, LOAD-OP is selfward with respect to
> COMPILE-OP, because in order to perform (load-op FILE), you must first perform (compile-op FILE). Your ECHO-OP has no such
> dependency. In this case, I believe you want ECHO-OP to be downward and sideways, meaning that (ECHO-OP MODULE)
> depends on (ECHO-OP MODULE-COMPONENT) for each of the children MODULE-COMPONENTs of the MODULE, and that
> (ECHO-OP SOURCE-FILE) depends on (ECHO-OP EARLIER-SOURCE-FILE) for each of the EARLIER-SOURCE-FILEs in
> SOURCE-FILE's :DEPENDS-ON list. This way, when you call (OPERATE 'ECHO-OP (FIND-SYSTEM "whatever")), ASDF will do a
> depth-first dependency-order traversal of your system.

After playing a little with downward and sideway, I can observe that
downward-operation provides a depth-search/"postorder" traversal for the
current system; sideway-operation provides a dependency-first traversal
for dependent systems.

* Note:
Use :force all with OPERATE to force reloading all dependent
systems. E.g. (asdf:operate 'echo-op:echo-op :echo-op-test :force :all)

* Question:
Why can't I subclass ASDF:OPERATION? This is unexpected since
ASDF:OPERATION is the base class for all operations.

My code:
----------- file: echo-op.lisp -------------------
(in-package #:echo-op)

(defclass echo-op (asdf:operation) ())

(defmethod asdf:perform ((op echo-op) c)
  (format t "~&Operation ~a on component ~a has input files:~{~%  ~a~}~%"
	  op c (asdf:input-files op c)))
-------------------------------------------------

Output:
----------------- REPL --------------------------
CL-USER> (asdf:operate 'echo-op:echo-op :echo-op-test :force t)
WARNING:
DEPRECATED-FUNCTION-WARNING: Using deprecated function (ASDF/ACTION::BACKWARD-COMPATIBLE-DEPENDS-ON
                                                        :FOR-OPERATION
                                                        #<ECHO-OP:ECHO-OP >) -- please update your code to use a newer API.
WARNING:
DEPRECATED-FUNCTION-WARNING: Using deprecated function (ASDF/ACTION::BACKWARD-COMPATIBLE-DEPENDS-ON
                                                        :FOR-OPERATION
                                                        #<ECHO-OP:ECHO-OP >) -- please update your code to use a newer API.
WARNING:
DEPRECATED-FUNCTION-WARNING: Using deprecated function (ASDF/ACTION::BACKWARD-COMPATIBLE-DEPENDS-ON
                                                        :FOR-OPERATION
                                                        #<ECHO-OP:ECHO-OP >) -- please update your code to use a newer API.
WARNING:
DEPRECATED-FUNCTION-WARNING: Using deprecated function (ASDF/ACTION::BACKWARD-COMPATIBLE-DEPENDS-ON
                                                        :FOR-OPERATION
                                                        #<ECHO-OP:ECHO-OP >) -- please update your code to use a newer API.
Operation #<ECHO-OP > on component #<CL-SOURCE-FILE "echo-op-test" "package"> has input files:
Operation #<ECHO-OP > on component #<CL-SOURCE-FILE "echo-op-test" "example"> has input files:
Operation #<ECHO-OP > on component #<CL-SOURCE-FILE "echo-op-test" "main"> has input files:
Operation #<ECHO-OP > on component #<SYSTEM "echo-op-test"> has input files:
#<ECHO-OP:ECHO-OP >
#<ASDF/PLAN:SEQUENTIAL-PLAN {1015FB0BC3}>
-------------------------------------------------

> 2. Your COMPONENT-DEPENDS-ON method is wrong. No pair of (OPERATION COMPONENT) should ever depend on the same
> (OPERATION COMPONENT). What you're saying is, "in order to perform (ECHO-OP FILE), you must first perform (ECHO-OP
> FILE)."
>
> 3. For operations that subclass one or more of DOWNWARD- UPWARD- SIDEWAY- SELFWARD- or
> NON-PROPOGATING-OPERATION, you don't need to define a COMPONENT-DEPENDS-ON method.

Why is my COMPONENT-DEPENDS-ON method wrong? It's not obvious that one
doesn't need to define a COMPONENT-DEPENDS-ON method for >=1
*-OPERATION. Is it stated anywhere?  

I'm following the manual: "If the action of performing the operation on a component has
dependencies, you must define a method on component-depends-on." and following the examples in cffi-grovel: https://github.com/cffi/cffi/blob/3c76afe7ba03ce015e0df99ac9ddcd61320a44a4/grovel/asdf.lisp#L66


That said, my code works fine by removing my COMPONENT-DEPENDS-ON
method. And I can see what you meant by (ECHO-OP FILE) depending on
itself by printing it out:

My code:
----------- file: echo-op.lisp -------------------
(in-package #:echo-op)

(defclass echo-op (asdf:sideway-operation asdf:downward-operation) ())

(defmethod asdf:perform ((op echo-op) c)
  (format t "~&Operation ~a on component ~a depends on ~{~%  ~a~}~%"
	  op c (asdf:component-depends-on op c)))
-------------------------------------------------

Output:
----------------- REPL --------------------------
CL-USER> (asdf:operate 'echo-op:echo-op :echo-op-test :force t)
Operation #<ECHO-OP > on component #<CL-SOURCE-FILE "echo-op-test" "package"> depends on 
(#<ECHO-OP >)
Operation #<ECHO-OP > on component #<CL-SOURCE-FILE "echo-op-test" "example"> depends on 
(#<ECHO-OP >)
Operation #<ECHO-OP > on component #<CL-SOURCE-FILE "echo-op-test" "main"> depends on 
(#<ECHO-OP >)
Operation #<ECHO-OP > on component #<SYSTEM "echo-op-test"> depends on 
(#<ECHO-OP >)
(#<ECHO-OP > #<CL-SOURCE-FILE "echo-op-test" "package">
	   #<CL-SOURCE-FILE "echo-op-test" "example">
	   #<CL-SOURCE-FILE "echo-op-test" "main">)
(DEFINE-OP echo-op-test)
#<ECHO-OP:ECHO-OP >
#<ASDF/PLAN:SEQUENTIAL-PLAN {10162397C3}>
-------------------------------------------------

But still I don't get why echo-op depends on itself. I didn't specify it
anyway. Or it that the default behaviour for all *-operation classes?

> 4. Most (OPERATION COMPONENT) pairs have very uninteresting sets of input files. (COMPILE-OP CL-SOURCE-FILE) has one
> input file, the .lisp source file. (LOAD-OP CL-SOURCE-FILE) has one input file, the .fasl compiled file. (ECHO-OP CL-SOURCE-FILE)
> will have no input files at all, unless you define a method on INPUT-FILES to list them.

Why do I get nothing for my input-files? I'm expecting it to print out
the pathname to (:FILE "foo") object, very much like the input files
into COMPILE-OP. 

Again, I thought ASDF is smart enough to infer it for me? To quote the manual:

"A method for this function is often not needed, since ASDF has a pretty
clever default input-files mechanism."

Is there a way to obtain the pathname to (:FILE "foo") from the
CL-SOURCE-FILE object like what COMPILE-OP does?

> I think the following definition of ECHO-OP might be enlightening to you:
>
> (uiop:define-package :echo-op
>   (:use :cl)
>   (:export #:echo-op))
> (in-package :echo-op)
>
> (defclass echo-op (asdf:sideway-operation asdf:downward-operation) ())
>
> (defun print-input-files (op c)
>   (format t "~&Operation ~a on component ~a has input files:~{~%  ~a~}~%"
>           op c (asdf:input-files op c)))
>
> (defun print-dependencies (op c)
>   (format t "~&Operation ~a on component ~a depends on ~{~%  ~a~}~%"
>           op c (asdf:component-depends-on op c)))
>
> (defmethod asdf:perform ((op echo-op) c)
>   (flet ((do-operations (thunk)
>            (funcall thunk op c)
>            (funcall thunk (asdf:make-operation 'asdf:compile-op) c)
>            (funcall thunk (asdf:make-operation 'asdf:load-op) c)))
>     (format t "~&~%Input files for component ~a with a variety of operations:~%~%" c)
>     (do-operations #'print-input-files)
>     (format t "~&~%Dependencies for component ~a with a variety of operations:~%~%" c)
>     (do-operations #'print-dependencies)))
>
> Note that:
> 1. The only method I have defined is on PERFORM, and it is a primary method, not an :AROUND method. ASDF already has all
> the COMPONENT-DEPENDS-ON methods I need.
> 2. I print the COMPONENT-DEPENDS-ON list in addition to the INPUT-FILES list.
> 3. I print both the COMPONENT-DEPENDS-ON and INPUT-FILES lists for all three of ECHO-OP, COMPILE-OP and LOAD-OP.
>
> I recommend you load this version, try (ASDF:OPERATE 'ECHO-OP:ECHO-OP (ASDF:FIND-SYSTEM "echo-op-test") :FORCE T) and
> see what output you get.

Thanks! It's indeed very enlightening. And I've separated it out into
few parts to play with, as shown in the code snippet I pasted above.

One question: How do you know whether to define PERFORM primary method
or an :AROUND method for the custom operation class? It's not obvious to
me which one to choose for different use cases.

Thanks!

-- 
Regards,
zacque



More information about the asdf-devel mailing list