cabal test with build-dep on self has surprising source directory behavior #1084

ezyang opened this Issue Oct 24, 2012 · 6 comments


None yet

3 participants

ezyang commented Oct 24, 2012

A common situation is to setup a Cabal package with a library and a test-suite for the library, e.g. for package 'foo', one might try:

  exposed-modules:     Foo

test-suite tests
  type: exitcode-stdio-1.0
  main-is: Foo/Test.hs
  build-depends: foo

This will not do what you want: in particular, when Foo/Test.hs is compiled, it will automatically pick up the source directory of the library (which is by default '.') and compile against Foo.hs directly, rather than pick up the Foo exported by the inplace installed 'foo' library.

Now, this might not be so bad, except occasionally you'll get mysterious type errors like:

    Couldn't match expected type `foo-'
                with actual type `Foo.Program'


    Ambiguous occurrence `F'
    It could refer to either `Foo.F',
                             imported from `Foo' at Test.hs:1:1-10
                             (and originally defined in `Bar')
                          or `Bar.F', imported from `Bar' at Test.hs:2:1-10

What's going on here? One way to make the bug manifest is when you depend on any source files which need a preprocessor run to generate the actual HS file (for example, a Happy or Alex file, or an hsc or c2hs file). Because those modules are not listed as "other-modules", Cabal will not build them, and then when GHC actually tries to build the original file, it will pick up the inplace installed library. You can probably also get this bug to show up in other cases too.

The workaround is to force the test-suite to use a different source directory, so it doesn't pick up library sources; Cabal should warn about that at least. But maybe there's a way to mask out exposed-modules from the test-suite compilation so we can have both of the source directories be the same.

A sample package which displays this problem is available here:

tibbe commented Oct 30, 2012

I've fixed the preprocessor issue for test suites and benchmarks in #1087.

tibbe commented Oct 30, 2012

I believe the issue is that when we compile using --make (which we do) GHC happily picks up any dependencies it can find on its search path. I can see us going one of two ways:

  • Require that all modules that should be compiled are listed in either exposed-modules or other-modules. We could enforce this by symlinking those modules into another directory and running the build there.
  • Get rid of other-modules entirely and always chase dependencies using the import statements in the files listed in exposed-modules or main-is.
ezyang commented Oct 30, 2012

Duncan and I talked about this a little, and I think Duncan claimed that (2) (tracing the dependencies manually) would be highly nontrivial and also inefficient, and it would just be better to keep asking people to explicitly specify modules in the Cabal file.

tibbe commented Oct 30, 2012

I'm fine with that. We should then try to design a mechanism that enforces that all dependencies are listed. Here's a strawman: symlink copy all the source files to a new directory before building. It would be nice to do this in such a way that we don't trigger unnecessary recompilation by GHC. A nice side-effect of this is that doing distributed compiles will be easier, as building outside the source tree will make sure that packages fully specify their dependencies (and are thus hermetic).

ghost commented Aug 30, 2013

As it happens, I just hit this with Alex + Happy, and happily (hee), using the suggested workaround (forcing the test-suite into a different directory) solved it.


@ttuegel ttuegel added this to the _|_ milestone Apr 23, 2015
ezyang commented Aug 15, 2016

So, this would get fixed if we fix #2982 (basically, you'd have to explicitly list the duplicate modules to suppress the warning, making it obvious that the library "shows up twice"), so I'm going to close this as a dupe of that.

@ezyang ezyang closed this Aug 15, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment