I have been making my first experiments with the bundle operations, to try to get a better understanding of this corner of ASDF.
One thing I see in the new documentation is the following:
(defclass bundle-op (basic-compile-op) + ;; NB: use of instance-allocated slots for operations is DEPRECATED + ;; and only supported in a temporary fashion for backward compatibility. + ;; Supported replacement: Define slots on program-system instead. ((build-args :initarg :args :initform nil :accessor extra-build-args) (name-suffix :initarg :name-suffix :initform nil) (bundle-type :initform :no-output-file :reader bundle-type) - #+(or clasp ecl) (lisp-files :initform nil :accessor extra-object-files))) + #+(or clasp ecl) (lisp-files :initform nil :accessor extra-object-files)) + (:documentation "base class for operations that bundle outputs from multiple components"))
I think this is worth a discussion, before we get it set in stone. I can see two reasons why putting this in the system definition ("slots on program-system)" instead of in the operation might not be desirable:
1. It violates "the Faré principle" of the person who knows getting to specify. The programmer of the system doesn't know where the user wants the bundle delivered, but by putting this information in the system definition, it's the programmer, not the user, who gets to choose. Compare this with the way output translations work, where it's the user who chooses, not the developer. Another analogy: it's like "make install" without PREFIX.
2. This makes things cumbersome when you have a system that has the same codebase, but multiple different entry points. Consider a compression program that uses the same codebase, but wants to deliver 2 different executables, "squish" (compress) and "unsquish" (decompress). If we have the build destination hard-coded into the system definition, this is impossible. I was just experimenting with such a case myself, and ended up with a main system and 4 "slashy" systems, one for each entry point. Not a disaster, but not obviously a Good Thing, either.
OTOH, putting slots on operations is a nuisance, because then we need to propagate those slot-values from operations to derived operations.
I think it would be good to ponder this issue a bit.
Cheers, r
On Wed, Sep 21, 2016 at 10:08 AM, Robert Goldman rpgoldman@sift.net wrote:
I have been making my first experiments with the bundle operations, to try to get a better understanding of this corner of ASDF.
One thing I see in the new documentation is the following:
(defclass bundle-op (basic-compile-op)
- ;; NB: use of instance-allocated slots for operations is DEPRECATED
- ;; and only supported in a temporary fashion for backward
compatibility.
- ;; Supported replacement: Define slots on program-system instead. ((build-args :initarg :args :initform nil :accessor extra-build-args) (name-suffix :initarg :name-suffix :initform nil) (bundle-type :initform :no-output-file :reader bundle-type)
#+(or clasp ecl) (lisp-files :initform nil :accessor
extra-object-files)))
#+(or clasp ecl) (lisp-files :initform nil :accessor
extra-object-files))
- (:documentation "base class for operations that bundle outputs from
multiple components"))
I think this is worth a discussion, before we get it set in stone. I can see two reasons why putting this in the system definition ("slots on program-system)" instead of in the operation might not be desirable:
- It violates "the Faré principle" of the person who knows getting to
specify. The programmer of the system doesn't know where the user wants the bundle delivered, but by putting this information in the system definition, it's the programmer, not the user, who gets to choose. Compare this with the way output translations work, where it's the user who chooses, not the developer. Another analogy: it's like "make install" without PREFIX.
The "Faré principle" says that he who knows should be able and/or required to specify, and he who doesn't know shouldn't be either able or required to specify.
In the case of build flags for extra libraries, certainly the author of one program cannot possibly know the flags required for another program that his transitively depends on, and shouldn't have to specify a list of libraries valid for all such transitive dependencies (assuming a single list can make do without mutual incompatibilities between libraries), and shouldn't even be able to specify libraries that would interfere with how transitive dependencies are built. Yet, this is how the broken design of putting flags in operations works.
NB: Once again, the design used to make sense as a kluge on top of ASDF 1 in which there couldn't be transitive dependencies linked into a different program, anyway, and modifying the ASDF system class hierarchy was not feasible or not desirable while adding operations was a given. I'm not blaming the author of asdf-ecl, Michael Goffioul, or its original maintainer Juan Jose Garcia Ripoll. I'm just saying the design was a heroic kluge in its time, and is completely broken in a modern context. And I am blaming whoever is defending this design today. (And I hope Daniel Kochmanski has stopped defending it.)
The analogy with Make would be that flags you pass to Make do not transmit transitively to all libraries that you build outside the current program. Because Make is a small build tool that isn't designed to build more than the current program. i.e. Make isn't geared to handle more than what ASDF considers is a single system (or primary system). In the C world, they need lots and lots of build systems, and complex "distributions" to coordinate the build of more than one system. Lisp, for all its kluges and legacy, is radically simpler.
- This makes things cumbersome when you have a system that has the same
codebase, but multiple different entry points. Consider a compression program that uses the same codebase, but wants to deliver 2 different executables, "squish" (compress) and "unsquish" (decompress). If we have the build destination hard-coded into the system definition, this is impossible. I was just experimenting with such a case myself, and ended up with a main system and 4 "slashy" systems, one for each entry point. Not a disaster, but not obviously a Good Thing, either.
Putting extra build flags in the operation forces every system to be built with the same entry point, that the user must specify. Putting the flags in the system allows each system to have its own entry point, that the user doesn't have to worry about.
For squish and unsquish, just have two different secondary systems. You found the solution yourself! That's the *correct* solution, and yes, a Good Thing, reproducible by any user without having to know magic different operate invocations for each subsystem.
There is no correct solution putting the flags in the operation.
OTOH, putting slots on operations is a nuisance, because then we need to propagate those slot-values from operations to derived operations.
I think it would be good to ponder this issue a bit.
See my other response about MAKE-OPERATION.
—♯ƒ • François-René ÐVB Rideau •Reflection&Cybernethics• http://fare.tunes.org Atheism is a non-prophet organization.