haskell / cabal

Official upstream development repository for Cabal and cabal-install
https://haskell.org/cabal
Other
1.61k stars 691 forks source link

How to specify flag A XOR flag B / reject install plan? (from darcs) #3742

Open ezyang opened 8 years ago

ezyang commented 8 years ago

In Darcs, there is some code that looks like this:

    if (!flag(curl) && !flag(http))
        buildable: False

I think the intent is to say, "Darcs needs either the curl or http flag to be turned on." But I don't think this is the right way to go about doing it: this says that it is acceptable for Cabal to set curl and http false; the only consequence is the library isn't buildable. If we somehow have a constraint that the library must be buildable, I suppose this has the desired effect if darcs is a dependency (I imagine the solver then requires the library to be buildable), but if you run cabal configure there's no reason to enable the library (well, if we want to build the executable there is, but you could also set the executable flag false and now nothing is built.)

Question 1: What's the right way to write the logic program that is desired here?

Question 2: How should we document this, and educate users to write logic programs that actually work?

I got this from #3740.

ezyang commented 8 years ago

CC @grayjay

phadej commented 8 years ago

What I see that there are three options:

Using binary flags, there aren't way to exclude the fourth option. Or at least using build-depends: base<0 would be better way.

Related: https://github.com/haskell/cabal/issues/3526

ezyang commented 8 years ago

base<0 is definitely better, it makes the solver reject the plan, as opposed to just toggling library to be not buildable.

hsenag commented 8 years ago

FWIW darcs.cabal has had flags that set the library to buildable: False for quite a while, but now it's started going wrong (only with GHC 8.0 AFAICT) I see the logical fallacy :-)

I will probably drop the -f-http option entirely from darcs.cabal as it doesn't add much, which will remove this block. Good to know the base<0 trick though, I was looking for some way to explicitly throw an error and failing.

BardurArantsson commented 8 years ago

(I hope this isn't excessively flippant...)

A1: Well, what about "^" (aka Xor in most languages)? I mean

Build-depends: curl [range omitted] ^ http [range omitted]

doesn't seem too bad to me? I'm probably missing something.

A2: Make it simpler to state your intent. I think A1 does that to some degree.

EDIT: Anyway, it's an idea, I suppose.

ezyang commented 8 years ago

@hsenag Thanks for volunteering to fix this Darcs side!

@BardurArantsson The reason to not do this is historically build-depends is a flat list of dependencies, not an arbitrary logical expression. So adding an xor operator would be quite a forward looking change with major syntax changes.

As for making the intent clearer, see #3526

dcoutts commented 7 years ago

We've considered adding more direct support for "fail" conditions. This is probably doable but will be much much easier once we replace the parser and the .cabal AST.

There's two related ideas:

  1. explicit failure, with error messages

    if !(flag(curl) xor flag(http))
       fail: one of curl or http must be used

    This is more or less equivalent to the existing tricks to make the solution impossible in some condition, but with more obvious intention and better error messages.

  2. multi-value enum flags

    flag transport
     values: none, curl, http
     default: curl

    This is interpreted as an enumeration, and one value must be set. Then instead of all flags being bools, e.g --constraint=darcs +curl -http they can be enums --constraint=darcs transport=curl.

hsenag commented 7 years ago

FWIW from the darcs perspective we don't really need either of these - discovering the problem led to us re-evaluating what we really needed. A single boolean flag was actually fine and it makes our code simpler.

It makes sense in principle to have something like these though.

23Skidoo commented 7 years ago

Multi-value enum flags are IMO nicer than explicit failures.