On 10/31/06, Duncan Coutts<div><span class="gmail_quote"><b class="gmail_sendername"></b> <<a href="mailto:duncan.coutts@worc.ox.ac.uk" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)">duncan.coutts@worc.ox.ac.uk
</a>> wrote:</span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
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.</blockquote><div><br><snip><br></div>
<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">configuration: available(foo >= 2)<br>cpp-options: -Denable_cool_feature</blockquote>
<div><br>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. <br><br>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:
<br> configuration: using(foo >= x)<br> ....<br>to always be written as:<br> flag: blah<br> default: avalable(foo >= x)<br><br> configuration: blah<br><br><br>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.
<br><br>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.
<br><br>
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.<br>
<br>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.
<br><br> Example 1:<br> Installed versions of foo: 1.0, 2.0, 3.0<br> Build-depends: foo >= 2.0<br><br>foo 3.0 is selected because it is the latest available version >= 2.0<br><br> Example 2:<br> Installed versions of foo:
1.0, 2.0, 3.0<br> Build-depends: foo < 2.0<br><br>foo 1.0 is used to build the package, because it is the latest version < 2.0<br><br> Example 3:<br> Installed versions of foo: 1.0, 2.0, 3.0<br> Build-depends: foo >=
2.0<br><br> Flag: bleeding-edge-features<br> Default: available(foo >= 3.0)<br> <br> configuration: bleeding-edge-features<br> Build-depends: foo >= 3.0<br> cpp-options: -DBLEED<br><br>(a) Additional user input: use
foo-2.0 <br>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).
<br><br>(b) Additional user input: --bleeding-edge-features, use foo-2.0<br>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".<br><br> Example 4:<br> Installed versions of foo: 1.0, 2.0, 3.0<br> Build-depends: foo >= 2.0<br> <br> Additional user input: none<br> Available for download:
foo-3.0, foo-4.0<br><br>foo-3.0 will be selected (the latest installed version, >= 2.0)<br>Nothing will be downloaded.<br><br> Example 5:<br> Installed versions of foo: 1.0, 2.0<br> Build-depends: foo >= 3.0
<br> <br> Available for download: foo-3.0, foo-4.0<br> Addtional user input: none<br>
<br>No installed versions of foo satisfy foo >= 3.0<br>If we are using Cabal (not cabal-get), then the build fails with an error.<br>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.<br><br> Example 6:<br> Installed versions of foo: 1.0, 2.0, 3.0<br> Build-depends: foo >= 2.0<br> Available for download:
foo-3.0, foo-4.0<br> Addtional user input: use foo-4.0<br><br>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.<br><br>
Example 7:<br> Build-depends: foo >= 2.0<br><br> Flag: use-old-version<br> Default: !available(foo >= 2.0)<br><br> Configuration: use-old-version<br> Build-depends: foo < 2.0<br> cpp-options: -DCOMPAT
<br><br>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.
<br><br> Example 8:<br> Build-depends: foo >= 1.0<br> <br> Flag: use-new-version<br> Default: available(foo >= 2.0)<br> <br> #Notice that this stanza is not needed: if availble(foo >= 2.0),<br> #then we are guaranteed to use such a version
<br> #Configuration: use-new-version<br> #Build-depends: foo >= 2.0<br><br> Configuratoin: !use-new-version<br> cpp-options: -DCOMPAT<br><br>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.<br><br> Example 9:<br> Build-depends: foo >= 2.0<br>
<br>
Flag: use-old-version<br>
Default: !available(foo >= 2.0)<br>
<br>
Configuration: use-old-version<br>
Build-depends: foo >= 1.0<br>
cpp-options: -DCOMPAT<br>
<br>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.
<br><br>Regards,<br>Brian<br><br></div></div>