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

Phil Ruffwind rf at rufflewind.com
Wed Sep 10 21:35:52 UTC 2014


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


More information about the Haskell-Cafe mailing list