issues with configurations
Duncan Coutts
duncan.coutts at worc.ox.ac.uk
Thu Aug 10 14:45:58 EDT 2006
Following long discussions on #haskell, here's some tricky cases we
thought of with configurations.
1.
build-depends: base
configuration: debug
build-depends: HUnit>=1.0
configuration: package(HUnit>=1.1)
ghc-options: -DBlah
The issue with this is what the "package(HUnit)" test means. Under one
interpretation it just tests if that package is available (ie already
installed), not if it's actually going to be used in this package.
Under the other interpretation this can't be expressed since HUnit is
not a top level dependency.
Alternatively we could evaluate the configurations in order, in which
case we've added HUnit>=1.0 to build depends before checking
package(HUnit>=1.1). But making it order-dependent is ugly.
2.
build-depends: base
configuration: package(hdbc)
build-depends: hdbc
configuration: package(hsql)
build-depends: hsql
This is not ideal since it suggests that we will just pick up optional
dependencies on packages if they are available with no control from the
user as to whether they want those dependencies. This also means that
the order in which you install packages can affect which features are
enabled which makes the use of a dep resolver like cabal-install less
intuitive as it becomes hard to predict how the packages will end up
getting built. Incidentally this conflicts with distro package mangers
like Gentoo's which specifically bans automatically picking up optional
deps. It requires that all optional deps be specified before hand and be
configurable by the user. This would also be difficult for binary
package managers like debian as the debian package would just have to
statically decide if hdbc or hsql or both will be used.
Again, one option is to ban this on account of neither dep being
mentioned in the top level build-depends.
A better way to express this dependency might be:
build-depends: base
configuration: hdbc
build-depends: hdbc
configuration: hsql
build-depends: hsql
This means that we have flags "hdbc" and "hsql" and the user must
specify at configure time --enable-hdbc or --disable-hdbc
This way the optional dependency is not automatic and can be changed by
the user. It's perfectly ok for there to be a default setting for the
flag so long as the user can override it. This is much like Gentoo's USE
flag system.
3.
build-depends: base
configuration: package(base<=1.0)
build-depends: fps>=0.8
This one is ok.
Is there a better way to do what we want without getting the bad cases?
I am of the opinion that it makes little sense for conditional package
tests to be of what packages are available in the environment rather
than packages that have actually been chosen for this package. Remember
that we can have multiple versions available so here's a case where 1.
falls over. Here's case 1. again:
1.
build-depends: base
configuration: debug
build-depends: HUnit>=1.0
configuration: package(HUnit>=1.1)
ghc-options: -DBlah
Suppose we have HUnit 1 and 2 installed. Suppose our package depends on
another package which needs HUnit-1. With the debug flag enabled we
depend on HUnit>=1.0. To pick a consistent HUnit version we must use 1.0
since we can't have two versions of the same package (even ghc's recent
support for this doesn't help if HUnit gets used in the interface since
the types would not match). So we pick HUnit-1.0. Now the configuration
test "package(HUnit>=1.1)" is still true because there is version 2
available, even though we're not using it! This is not an intuitive
semantics.
If we say that package() tests must refer to packages we're going to
actually build against on then this is fine and we get what the package
author probably meant.
So this suggests we should limit package() tests to packages that we
depend on or might depend on.
But for 1. we still have the issue of the order of evaluation of
configuration stanzas being significant because they can add packages to
build-depends which other stanzas may test.
In gentoo such a dependency might be expressed as:
DEPEND="debug? ( HUnit>=1.0 )"
but then the action dependent on the version of HUnit that we picked
would be done later. So there's a clear ordering.
So one solution is to not allow build-depends in conditional stanzas but
to specify conditional depends up front.
build-depends: base, debug? ( HUnit>=1.0 )
configuration: debug
ghc-options: -DDEBUG
configuration: package(HUnit>=1.1)
ghc-options: -DBlah
or:
build-depends: base > 1.0 || ( base <= 1.0 && fps >= 0.8 ),
os(windows)? ( Win32 ),
os(linux)? ( inotify )
configuration: package(fps)
ghc-options: -DOLD_FPS
configuration: package(base < 1.1)
hs-src-dirs: compat
So I guess the suggestion is that all deps are given up front and
resolved. Then depending on what deps were chosen we can have other
effects on the build like specifying extra src dirs or flags or
whatever, but not specifying any more build-depends. So the order of
checking configurations is independent again.
Ok I've gone on long enough.
Duncan
More information about the cabal-devel
mailing list