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