Is it just me, or is the :FEATURE dependency-def form undocumented in the manual? It is *mentioned* in the grammar, but I don't see it documented -- except for the misleading mention that the :FEATURE *requirement* has been removed from ASDF.
# This is used in :depends-on, as opposed to ``dependency,'' # which is used in :in-order-to dependency-def := simple-component-name | ( :feature FEATURE-EXPRESSION dependency-def ) | ( :version simple-component-name version-specifier ) | ( :require module-name )
I'm actually not sure what the semantics of this should be:
1. if the FEATURE is present, include dependency-def and 2a. If the FEATURE is absent FAIL or 2b. If the FEATURE is absent, quietly succeed.
If the semantics is intended to be the latter -- and that's how I read the relevant code in find-component.lisp -- how does a programmer say "if this feature is not present, my system should not compile"?
I stubbed my toe on this absent-mindedly compiling Didier's decLt system on Allegro Common Lisp.
That system doesn't, and cannot, function on ACL, but ASDF tells us it has compiled successfully.
Instead, what seems to happen is that the net.didierverna.declt.core system depends on (:feature :sbcl :sb-introspect) which simply seems to fail quietly on ACL, in what looks like the worst possible way: the attempt to laod net.didierverna.declt returns T, the guts of the system is not loaded (seems like this feature system somehow keeps core from continuing to load), and no error message is issued.
Actually, I don't claim to understand why this happens -- it looks to me like RESOLVE-DEPENDENCY-SPEC should return NIL, and the load should continue (trying to load the :net.didierverna.declt.core system and succeeding -- or more likely choking when it hits a reference to :SB-INTROSPECT). But somehow it's failing to load.
I'll see if I can make a minimal test case and file a bug, but I could use some guidance about what was intended. If the semantics of :FEATURE are like those of :IF-FEATURE, as I suspect, it seems like they aren't working here. And, if that's what's intended, how do we get the "fail if this feture is absent" behavior that a programmer might like?
thanks, r
On Mon, May 16, 2016 at 3:35 PM, Robert Goldman rpgoldman@sift.net wrote:
Is it just me, or is the :FEATURE dependency-def form undocumented in the manual? It is *mentioned* in the grammar, but I don't see it documented -- except for the misleading mention that the :FEATURE *requirement* has been removed from ASDF.
There were two :FEATURE features. One was braindead and I removed it in ASDF3, because it was badly breaking the object model.
- if the FEATURE is present, include dependency-def and
2a. If the FEATURE is absent FAIL or 2b. If the FEATURE is absent, quietly succeed.
2b. Basically it's a (:when-feature :foocl "foocl-support") Maybe it should have been named :when-feature, but I believe the name was also from ASDF1, except that that feature feature was badly broken and I had to fix it!
If the semantics is intended to be the latter -- and that's how I read the relevant code in find-component.lisp -- how does a programmer say "if this feature is not present, my system should not compile"?
(:feature (:not :foocl) "something_that_fails")
—♯ƒ • François-René ÐVB Rideau •Reflection&Cybernethics• http://fare.tunes.org With freedom, no more One True Scale to rank people. Everyone pick his own. Why vie for a society of equals, when everyone can be superior?
On 5/16/16 May 16 -4:36 PM, Faré wrote:
On Mon, May 16, 2016 at 3:35 PM, Robert Goldman rpgoldman@sift.net wrote:
Is it just me, or is the :FEATURE dependency-def form undocumented in the manual? It is *mentioned* in the grammar, but I don't see it documented -- except for the misleading mention that the :FEATURE *requirement* has been removed from ASDF.
There were two :FEATURE features. One was braindead and I removed it in ASDF3, because it was badly breaking the object model.
Right. I believe that's the one documented as "feature requirement."
Some of this is a problem that arises because we don't have a DEFSYSTEM *Semantics* section, only a DEFSYSTEM *grammar*.
- if the FEATURE is present, include dependency-def and
2a. If the FEATURE is absent FAIL or 2b. If the FEATURE is absent, quietly succeed.
2b. Basically it's a (:when-feature :foocl "foocl-support") Maybe it should have been named :when-feature, but I believe the name was also from ASDF1, except that that feature feature was badly broken and I had to fix it!
OK. I will try to add a subsection about the semantics to the defsystem grammar page (per my earlier remarks, not ideal, but I'm not ready to plunge into the end-to-end rewrite and reorg that the manual requires!).
If the semantics is intended to be the latter -- and that's how I read the relevant code in find-component.lisp -- how does a programmer say "if this feature is not present, my system should not compile"?
(:feature (:not :foocl) "something_that_fails")
Would it be possible for us to either add something that fails as
(:feature (:not :foocl) :fail)
or perhaps better (the above smells uncomfortably like :IF-COMPONENT-DEP-FAILS):
(:required-feature <feature-expression>)
"require" is, perhaps unfortunately, a term of art for CL so perhaps
(:must-have-feature <feature-expression>)
would be better....
One more query while I have you on the line:
the grammar still contains this rule:
component-dep-fail-option := :fail | :try-next | :ignore
The LHS of that rule is never referenced, so I propose to cut it.
Thanks for the advice & clarification, r
On Mon, May 16, 2016 at 5:56 PM, Robert Goldman rpgoldman@sift.net wrote:
On 5/16/16 May 16 -4:36 PM, Faré wrote:
On Mon, May 16, 2016 at 3:35 PM, Robert Goldman rpgoldman@sift.net wrote: There were two :FEATURE features. One was braindead and I removed it in ASDF3, because it was badly breaking the object model.
Right. I believe that's the one documented as "feature requirement."
Indeed.
Some of this is a problem that arises because we don't have a DEFSYSTEM *Semantics* section, only a DEFSYSTEM *grammar*.
Yes.
OK. I will try to add a subsection about the semantics to the defsystem grammar page (per my earlier remarks, not ideal, but I'm not ready to plunge into the end-to-end rewrite and reorg that the manual requires!).
I won't cast the first stone.
If the semantics is intended to be the latter -- and that's how I read the relevant code in find-component.lisp -- how does a programmer say "if this feature is not present, my system should not compile"?
(:feature (:not :foocl) "something_that_fails")
Would it be possible for us to either add something that fails as
(:feature (:not :foocl) :fail)
This should already fail... if there's no system or component named fail.
or perhaps better (the above smells uncomfortably like :IF-COMPONENT-DEP-FAILS):
(:required-feature <feature-expression>)
"require" is, perhaps unfortunately, a term of art for CL so perhaps
(:must-have-feature <feature-expression>)
would be better....
The traditional solution was to fail at compile-time and/or load-time with a #-(or clozure sbcl) (error "not supported implementation")
That's what asdf itself does, btw.
I recommend against failing while loading the .asd file, because that will break cross-compilation in the future (and/or on MOCL, which already does it with a gross hack).
One more query while I have you on the line:
the grammar still contains this rule:
component-dep-fail-option := :fail | :try-next | :ignore
The LHS of that rule is never referenced, so I propose to cut it.
Yes, that was part of the :if-component-dep-fail misfeature that I removed in ASDF3.
—♯ƒ • François-René ÐVB Rideau •Reflection&Cybernethics• http://fare.tunes.org Beware of altruism. It is based on self-deception, the root of all evil. — Robert Heinlein, "Time Enough For Love"
Robert Goldman rpgoldman@sift.net écrivait:
I stubbed my toe on this absent-mindedly compiling Didier's decLt system on Allegro Common Lisp. That system doesn't, and cannot, function on ACL, but ASDF tells us it has compiled successfully.
Following up to our private conversation on this...
I think there's an error on my part to begin with. The core system of Declt has an :if-feature :sbcl, which prevents it from being loaded outside SBCL. This is mostly what's needed, but I hadn't realized that it /silently/ does so, instead of throwing an error if the feature is absent.
So the question is: can I declaratively state that a system (or maybe more generally a component) depends on a feature, so that loading fails with an error otherwise ? I don't currently see a way.
In fact, it seems to me that the current :depends-on (:feature :this :that) syntax is a misnomer. Perhaps it would have been more explicit to write :depends-on (:if-feature :this :that) in order to express that the conditional actually may fail silently.
Now, what about extending the syntax with: :depends-on (:feature :this) to actually mean "if :this is not on the features list, fail with an error"?
Robert Goldman rpgoldman@sift.net écrivait:
I stubbed my toe on this absent-mindedly compiling Didier's decLt system on Allegro Common Lisp. That system doesn't, and cannot, function on ACL, but ASDF tells us it has compiled successfully.
Following up to our private conversation on this...
I think there's an error on my part to begin with. The core system of Declt has an :if-feature :sbcl, which prevents it from being loaded outside SBCL. This is mostly what's needed, but I hadn't realized that it /silently/ does so, instead of throwing an error if the feature is absent.
So the question is: can I declaratively state that a system (or maybe more generally a component) depends on a feature, so that loading fails with an error otherwise ? I don't currently see a way.
#-feature (error "FEATURE missing")
at toplevel, so you get an error on reading the .asd file.
Stelian Ionescu wrote:
#-feature (error "FEATURE missing")
at toplevel, so you get an error on reading the .asd file.
Of course. I said a "declarative way" within the system itself tho ;-)
On Tue, May 17, 2016 at 9:39 AM, Didier Verna didier@lrde.epita.fr wrote:
Stelian Ionescu wrote:
#-feature (error "FEATURE missing")
at toplevel, so you get an error on reading the .asd file.
Of course. I said a "declarative way" within the system itself tho ;-)
I strongly recommend against erroring in the .asd file itself based on the implementation, because that hinders cross-compilation.
The traditional solution is to load a file that fails. i.e. create a file unsupported-implementation.lisp that has an (error ...) form and in your asd file, use a component (:file "unsupported-implementation" :if-feature (:not :sbcl))
And yes, I probably should have called it :when-feature instead of :if-feature. My bad. If you think that's worth it, we can add the new name now and remove the old name in 2 years.
PS: Robert, I pushed a tiny tweak to the documentation.
—♯ƒ • François-René ÐVB Rideau •Reflection&Cybernethics• http://fare.tunes.org If you're wrong against the dominant ideology, you'll be laughed at. If you're right against the dominant ideology, you'll be hated.
On 5/17/16 May 17 -8:47 AM, Faré wrote:
On Tue, May 17, 2016 at 9:39 AM, Didier Verna didier@lrde.epita.fr wrote:
Stelian Ionescu wrote:
#-feature (error "FEATURE missing")
at toplevel, so you get an error on reading the .asd file.
Of course. I said a "declarative way" within the system itself tho ;-)
I strongly recommend against erroring in the .asd file itself based on the implementation, because that hinders cross-compilation.
IIUC what this boils down to is a preference for failing to *operate* on the system, rather than failing to parse the system definition. Correct?
[As an aside, there may be a separate bug: when I tried to load DecLt into ACL, the loading *succeeded*, but the contents of the decLt "core" subsystem failed to be loaded. So I believe there may be an oddity in the way ASDF is handling these "failed" :feature dependencies. I will try to replicate and provide a minimal test case.]
The traditional solution is to load a file that fails. i.e. create a file unsupported-implementation.lisp that has an (error ...) form and in your asd file, use a component (:file "unsupported-implementation" :if-feature (:not :sbcl))
I would prefer that we provide a more readable version of this. I think we could readily add
(:depends-on (:essential-feature :sbcl))
As I said earlier, the "bogus file" solution seems to me unpleasantly indirect, because then the poor reader must grovel over "unsupported-implementation" to see what will happen if one tries to load it, when the intent is simply to say "this won't work unless you are on SBCL."
I believe we could provide this with the semantics you propose (fail on operation, not on loading the system definition).
And yes, I probably should have called it :when-feature instead of :if-feature. My bad. If you think that's worth it, we can add the new name now and remove the old name in 2 years.
PS: Robert, I pushed a tiny tweak to the documentation.
Thanks, I'll pull and have a look now.
best, r
: Faré
: Robert
I strongly recommend against erroring in the .asd file itself based on the implementation, because that hinders cross-compilation.
IIUC what this boils down to is a preference for failing to *operate* on the system, rather than failing to parse the system definition. Correct?
If we ever want to support cross-compilation, it's more than a preference: it's a bug to fail to load an .asd file just because the system won't load on the current (master) implementation — it is meant to work on the (slave) cross-implementation.
[As an aside, there may be a separate bug: when I tried to load DecLt into ACL, the loading *succeeded*, but the contents of the decLt "core" subsystem failed to be loaded. So I believe there may be an oddity in the way ASDF is handling these "failed" :feature dependencies. I will try to replicate and provide a minimal test case.]
I'd say it's a bug in DecLt rather than ASDF. It's :if-feature :sbcl says that the system is a NOP when the target implementation isn't sbcl. If what is intended instead is that the system should error out when the implementation isn't sbcl, it should use something like :depends-on (... (:feature (:not :sbcl) "implementation-not-supported") ...) or to be cleaner: :components ((:file "implementation-not-supported" :if-feature (:not :sbcl)))
The traditional solution is to load a file that fails. i.e. create a file unsupported-implementation.lisp that has an (error ...) form and in your asd file, use a component (:file "unsupported-implementation" :if-feature (:not :sbcl))
I would prefer that we provide a more readable version of this. I think we could readily add
(:depends-on (:essential-feature :sbcl))
I don't like that name, and I don't like abusing :depends-on for it. If you want an error when compiling outside a given set of implementations, maybe it's better having a defsystem option. it doesn't make sense at the component level, so let's not hack the depends-on language for it. (defsystem declt ... :error-if-not-feature :sbcl ...)
:(fail|error)-(if-not|unless)(|-feature) :only-build-(on|with-feature) :demand-feature
As I said earlier, the "bogus file" solution seems to me unpleasantly indirect, because then the poor reader must grovel over "unsupported-implementation" to see what will happen if one tries to load it, when the intent is simply to say "this won't work unless you are on SBCL."
That's quite a reasonable feature request.
I was only describing the current "best practice".
I believe we could provide this with the semantics you propose (fail on operation, not on loading the system definition).
You could fail while building the plan, rather than performing it. Building a plan is already feature-dependent. That would save users a lot of patiently waiting for dependencies to build until they get their doomed answer.
—♯ƒ • François-René ÐVB Rideau •Reflection&Cybernethics• http://fare.tunes.org Live as if you were living already for the second time and as if you had acted the first time as wrongly as you are about to act now! — Viktor Frankl, "Man's Search for Meaning"
François-René ÐVB Rideau wrote:
The traditional solution is to load a file that fails. i.e. create a file unsupported-implementation.lisp that has an (error ...) form and in your asd file, use a component (:file "unsupported-implementation" :if-feature (:not :sbcl))
Hmmm, ok but then, if you're to error in a Lisp file proper, why use the ASDF logic at all? I mean, why not just depend on the file as a regular one and perform all the tests that you need from Lisp code?
On Fri, May 20, 2016 at 1:11 PM, Didier Verna didier@lrde.epita.fr wrote:
François-René ÐVB Rideau wrote:
The traditional solution is to load a file that fails. i.e. create a file unsupported-implementation.lisp that has an (error ...) form and in your asd file, use a component (:file "unsupported-implementation" :if-feature (:not :sbcl))
Hmmm, ok but then, if you're to error in a Lisp file proper, why use the ASDF logic at all? I mean, why not just depend on the file as a regular one and perform all the tests that you need from Lisp code?
The reason to use ASDF logic would be to have multiple files, one for each implementation, and a fallback file for unsupported implementations.
You can also wholly avoid ASDF logic, by using your own build script, or using Bazel. One advantage of Bazel is that it currently only supports SBCL, so you don't have to support other implementations.
—♯ƒ • François-René ÐVB Rideau •Reflection&Cybernethics• http://fare.tunes.org Certainly the game is rigged. Don't let that stop you; if you don't bet, you can't win. — Robert Heinlein, "Time Enough For Love"