
On Fri, 2006-08-11 at 15:08 +0100, Duncan Coutts wrote:
On Fri, 2006-08-11 at 12:15 +0100, Simon Marlow wrote:
The whole thing is easier to understand IMO, and it's simple to implement too: no ordering, conditionals can be evalutated independently.
I think that having the semantics of 'package()' in a configuration test be to just check for the availability of a package in the environment must be wrong. It's usually not what you want, and when it is what you want you shouldn't be doing it! :-)
Ok so let me try and propose something concrete: build-depends := [package-with-version] flag := 'flag:' name 'default:' fexp -- flag default value expression fexp := '(' cexp ')' | cexp '||' cexp | cexp '&&' cexp | '!' cexp | 'True' | 'False' | 'os' '(' string ')' | 'arch' '(' string ')' | 'compiler' '(' string ')' -- this is the important one: | 'available' '(' package-with-version ')' configuration := 'configuration:' cexp -- configuration predicate expression cexp := '(' cexp ')' | cexp '||' cexp | cexp '&&' cexp | '!' cexp | 'os' '(' string ')' | 'arch' '(' string ')' | 'compiler' '(' string ')' -- these are the important ones: | 'flag' '(' string ')' | 'using' '(' package-with-version ')' So, semantics... Default values of flags can be evaluated independently and up front. The only non trivial test is the 'available' one. This checks if a package exists in the environment with that name and with a version that satisfies any given version range. "available (A>1) && available (A<1)" means (exists A. A>1) && (exists A. A<1), so they do not need to be the same A. Where as "available (A >1 <1)" would refer to the same A and therefore not be satisfiable. Configurations are evaluated in order, top to bottom (can we do better? require them to be acyclic?). Each configuration predicate can be evaluated based only on knowing the values of the flags (which may come from their default values or be overridden by the user) and the set of packages we are committed to. The 'using' test is the only non-trivial one. This checks if we are committed to depending on a version of the named package that satisfies the version range. We discover this by starting with the top level build depends. We do the normal checks to decide which version of each package we are going to depend upon. Once we know that then we can evaluate the 'using' tests. Of course a configuration may add extra build-depends and this can effect the value of a 'using' test in later configurations. How does this interact with the possibility of using multiple versions of a dependent package? In that case 'using' refers to any of the versions. So if we end up using Foo-1.0 and Foo-1.1 then both configurations are active: configuration: using(Foo>1.0) configuration: using(Foo<=1.0) Is there any way to make the order of configurations not matter? suppose I've got a configuration: configuration: using(Foo) build-depends: Bar configuration: using(Bar) build-depends: Foo We could ban it, or do it in order, or iterate 'til fixpoint. I think iterating 'til fixpoint would be terminating. Duncan