On why 'available' is evil

Brian Smith brianlsmith at gmail.com
Wed Nov 1 00:31:15 EST 2006


On 10/31/06, Duncan Coutts <duncan.coutts at worc.ox.ac.uk > wrote:
>
> In all this discussion on configurations I think I'm not getting over my
> main point about why we can't go for the 'easy' option of allowing package
> 'available' tests everywhere.


<snip>

configuration: available(foo >= 2)
> cpp-options: -Denable_cool_feature


I think that everybody already agrees that available(x) should not be
allowed in cexp's. You've always been clear about the disadvantages of
allowing that.

My point is that using(x) should not be allowed in cexp's either. I
suggestion the following rules, which would eliminate the need for using(x),
by allowing a configuration like this:
     configuration: using(foo >= x)
     ....
to always be written as:
     flag: blah
     default: avalable(foo >= x)

    configuration: blah


1. If Cabal is not given an explicit package version number to use, then it
will always choose the latest already-installed version of that package that
satisfies the effective Build-depends constraints. This is already how it
works right now.

2. If Cabal is told to use a specific version of a package (e.g. on the
command line), then available(x) will return false for all versions of that
package except for the version that the user requested. If that
specifically-requested version fails to satisfy any effective
configurations' Build-Depends for that package, then the build stops with an
error.

3. If Cabal-get can satisfy a dependency without downloading a different
(usually newer) version of a package, then it will do so. Otherwise, it will
download and installed the latest available version of the package that
satisfies the effective Build-depends in the package description.

4. The effective Build-depends in the intersection of the main stanza's
Build-depends with the Build-depends of all enabled configurations.
Effectively, a configuration cannot loosen or remove the dependencies given
in the main stanza--a configuration can only restrict the dependencies.

    Example 1:
    Installed versions of foo: 1.0, 2.0, 3.0
    Build-depends: foo >= 2.0

foo 3.0 is selected because it is the latest available version >= 2.0

    Example 2:
    Installed versions of foo: 1.0, 2.0, 3.0
    Build-depends: foo < 2.0

foo 1.0 is used to build the package, because it is the latest version < 2.0

    Example 3:
    Installed versions of foo: 1.0, 2.0, 3.0
    Build-depends: foo >= 2.0

    Flag: bleeding-edge-features
    Default: available(foo >= 3.0)

    configuration: bleeding-edge-features
    Build-depends: foo >= 3.0
    cpp-options: -DBLEED

(a) Additional user input: use foo-2.0
The user did not give the bleeding-edge-features flag, so its default is
used. Since the user selected foo-2.0 explicitly, then available(foo >= 3.0)
is false (when a specific version is selected, all other versions are made
unavailable). Thus, the bleeding-edge-features flag is not enabled
automatically, so the corresponding configuration is not used, (no -DBLEED).

(b) Additional user input: --bleeding-edge-features, use foo-2.0
The user forced the bleeding-edge-features flag, so the corresponding
configuration is used. But, that configuration requires foo >= 3.0. The
build stops with an error because foo >= 3.0 is not available due to the
"use foo-2.0".

    Example 4:
    Installed versions of foo: 1.0, 2.0, 3.0
    Build-depends: foo >= 2.0

    Additional user input: none
    Available for download: foo-3.0, foo-4.0

foo-3.0 will be selected (the latest installed version, >= 2.0)
Nothing will be downloaded.

    Example 5:
    Installed versions of foo: 1.0, 2.0
    Build-depends: foo >= 3.0

    Available for download: foo-3.0, foo-4.0
    Addtional user input: none

No installed versions of foo satisfy foo >= 3.0
If we are using Cabal (not cabal-get), then the build fails with an error.
If we are using cabal-get (not just Cabal) then there are two versions of
foo available for download that satisfy it. Cabal-get will download and
register foo-4.0 (the latest version that satisfies the constraint) Then,
Cabal will build the package using foo-4.0.

    Example 6:
    Installed versions of foo: 1.0, 2.0, 3.0
    Build-depends: foo >= 2.0
    Available for download: foo-3.0, foo-4.0
    Addtional user input: use foo-4.0

Although foo-2.0 and foo-3.0 are installed neither one will satisfy foo >=
3.0 because "use foo-4.0" effectively hides all versions except 4.0. Since
foo-4.0 is available for download, Cabal-get will download and register it.
Then, Cabal will build the package using foo-4.0.

     Example 7:
     Build-depends: foo >= 2.0

    Flag: use-old-version
    Default: !available(foo >= 2.0)

    Configuration: use-old-version
    Build-depends: foo < 2.0
    cpp-options: -DCOMPAT

Here, the user is trying to loosen the dependencies from the main stanza
using a flag. But, as I stated in rule 4 above, the build-depends are always
taken as intersections. That is, we have (foo >= 2.0) && (foo < 2.0) = { },
so the build fails. Notice that Cabal can (and should) determine statically
that the Build-depends of the configuration is mutually exclusive with the
build-depends of the main stanza and thus issue an error/warning.

    Example 8:
    Build-depends: foo >= 1.0

    Flag: use-new-version
    Default: available(foo >= 2.0)

    #Notice that this stanza is not needed: if availble(foo >= 2.0),
    #then we are guaranteed to use such a version
    #Configuration: use-new-version
    #Build-depends: foo >= 2.0

    Configuratoin: !use-new-version
    cpp-options: -DCOMPAT

This is a reformulation of Example 7 that actually works as intended: If foo
>= 2.0 is not availabe, then we define COMPAT, otherwise, we don't.

    Example 9:
    Build-depends: foo >= 2.0

    Flag: use-old-version
    Default: !available(foo >= 2.0)

    Configuration: use-old-version
    Build-depends: foo >= 1.0
    cpp-options: -DCOMPAT

Here is another reformulation of Example 7. Notice that the Build-depends of
the main stanza is more restrictive than the build-depends of the
configuration. This is a good indication that the user does not understand
how Build-depends are combined, so a warning/error should be issued.

Regards,
Brian
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/cabal-devel/attachments/20061031/c38cb5eb/attachment-0001.htm


More information about the cabal-devel mailing list