[Haskell-cafe] Cabal doesn't reset the search-path when invoking GHC: potential subtleties

Erik Hesselink hesselink at gmail.com
Thu Sep 11 07:35:20 UTC 2014


I think the solution to this problem usually is to have a separate
source directory for each component of your package (library,
executable, test suite, etc). For example, put the library in 'src',
and the executable in 'exe'. This way source files won't mix, and the
executable can depend on the library in the same package, so that
source files are only compiled once.

I don't think a solution with all files in a single directory is
possible in general, since the executable might also need more source
files not included in the library.

Erik

On Wed, Sep 10, 2014 at 11:35 PM, Phil Ruffwind <rf at rufflewind.com> wrote:
> It seems that even when invoked via Cabal, GHC will look in the local
> directory *first* and then in the list of modules and dependencies supplied by
> Cabal.  I was aware of this behavior subconsciously but I hadn't realized the
> implications until now.
>
> Normally, it's not a big problem, other than for the occasional situation
> where I forget to add those local modules to 'other-modules'.  This would
> cause 'cabal sdist' to generate an incomplete package, even though 'cabal
> build && cabal install' works just fine!
>
> But there are more subtle "bugs": it breaks if the executable and library
> share the same directory, but the library has some hidden modules stashed away
> in a different directory!  The conditions required to reproduce this is
> somewhat difficult to explain, so let me show a simple example:
>
>  1. Make a Cabal package:
>
>         -- ./foo.cabal
>         name:              foo
>         version:           0.0.0.0
>         build-type:        Simple
>         cabal-version:     >=1.8
>         library
>           exposed-modules: Exposed
>           other-modules:   Hidden
>           build-depends:   base
>           hs-source-dirs:  ., hidden
>         executable main
>           main-is:         Main.hs
>           build-depends:   base, foo
>
>  2. Add a library with two modules at the given paths:
>
>         -- ./Exposed.hs
>         module Exposed where
>         import Hidden
>
>         -- ./hidden/Hidden.hs
>         module Hidden where
>
>  3. Add an executable:
>
>         -- ./Main.hs
>         module Main where
>         import Exposed
>         main = return ()
>
>  4. Now run `cabal build`.  This would cause an error message akin to:
>
>     > Could not find module Hidden
>
> The problem is that despite the dependency on the library `foo` being
> specified in Cabal, GHC still chose the *local* `Exposed` module over the
> `Exposed` module in the library `foo`.  This means when it tries to recompile
> the `Exposed` module, it is unaware that `Hidden` is located in another
> directory.
>
> The error message is unhelpful because it doesn't point to the actual cause of
> the problem and led me astray thinking that something was wrong with my Cabal
> configuration.
>
> In the end, the problem has to do with GHC deciding to look up packages in
> locations outside Cabal's control.  There are many other ways to trigger this
> problem -- the above was only one that I just happened to run into.
>
> For now, a workaround would be to use `-i` with all the executables to avoid
> this subtle issue in the future.
>
> RF
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe


More information about the Haskell-Cafe mailing list