Defining CH executables in cabal files

Duncan Coutts duncan.coutts at googlemail.com
Thu Apr 4 17:10:06 CEST 2013


On Thu, 2013-04-04 at 15:46 +0100, Rob Stewart wrote:
> Hi Duncan, Edsko.
> 
> I'd like to know where I should most appropriately submit a bug
> report, or indeed whether the behaviour that I am experiencing is a
> bug or a user misuse of cabal.

It's a consequence of a misunderstanding of how package names affect
types and how different cabal constructs give you different package
names.

> I have packaged up a very simple send/receive example into a cabalised
> archive. In there is a README that describes the problem succinctly,
> though I will repeat here for convenience. It appears to be weirdness
> with main-is and hs-source-dirs. In the .cabal file, there are three
> executables of the same Receiver.hs file - a receiver of a CH message.
> One appears to be defined in such a way that the CH primitives `match`
> and `expect` are *not* receiving the message types that are being sent
> by Sender.hs.

The problem is that your three programs are using different types.

ch-receiver-1 and ch-receiver-2 use the type

        cabal-with-ch-executables-1.0:Bar.Baz.Types.Msg

while ch-receiver-3 uses the type

        Bar.Baz.Types.Msg

Those are the fully-qualified names of those types and they are
different, so they are different types, so have different Typeable
fingerprints and so the `expect` does not match them.

So as you can see, the fully qualified name of a type includes its
package id, and in the first case it has the package name
cabal-with-ch-executables-1.0 while in the second case it is the "home"
package, which has no name (or if you like, it's called "").

Code in a library has fully qualified names that include the package
name. Code in a top level executable is in the "home" package.

The way you've constructed your three programs, the first two put the
module in a library and the third puts it in the top level executable,
so according to ghc it really is a different module.

So lets look at your cabal file:

> library
>   default-language: Haskell2010
>   exposed-modules: Bar.Baz.Types
>                  , Bar.Baz.Identify
>   build-depends: base >= 4 && < 5
>                , binary >= 0.6.3.0
>                , bytestring >= 0.9.2
>                , distributed-process >= 0.4.2
>                , network
>                , network-transport
>                , network-transport-tcp
>   hs-source-dirs: src
>   GHC-Options: -Wall
>
> -- Works
> Executable ch-receiver-1
>   default-language: Haskell2010
>   main-is:        Receiver.hs
>   build-depends: base
>                , distributed-process
>                , network-transport-tcp
>                , network-transport
>                , cabal-with-ch-executables
>   hs-source-dirs: examples
>   ghc-options: -Wall
> 
> -- Works
> Executable ch-receiver-2
>   default-language: Haskell2010
>   main-is:        Receiver.hs
>   build-depends: base
>                , distributed-process
>                , network-transport-tcp
>                , network-transport
>                , cabal-with-ch-executables
>   hs-source-dirs: src/Bar/Baz
>   ghc-options: -Wall
> 
> -- Doesn't work
> Executable ch-receiver-3
>   default-language: Haskell2010
>   main-is:       Bar/Baz/Receiver.hs
>   build-depends: base
>                , distributed-process
>                , network-transport-tcp
>                , network-transport
>                , cabal-with-ch-executables
> 
>                -- I don't understand why these below are now needed??
>                , binary >= 0.6.3.0
>                , bytestring >= 0.9.2
>                , distributed-process >= 0.4.2
>                , network
>                , network-transport
>                , network-transport-tcp
>   hs-source-dirs: src
>   ghc-options: -Wall

So you have the first two executables depending on the library and they
pick up their Bar.Baz.Types module from the library.

Your third executable also depends on the library but the way you have
the sources organised means that you're getting the modules from the
source files and not from the library. This is because you're using the
hs-source-dirs as src, which is where the modules for the library live.
ghc will always pick local source files over modules from packages. This
is also why you needed those extra dependencies, your executable is
including those modules directly (you'll notice they're recompiled for
the 3rd exe).

The solution is that when you want to have an exe in a package depend on
a lib in the same package, you need to separate the src dirs, as you did
with the first one (hs-source-dirs: examples).

Clear as mud?

What would be good is if cabal would warn when the same module can be
found both in a local lib that we depend on, and as a source file,
because that's probably a mistake. It might also be good if we could
tell ghc where to get the modules from explicitly, rather than rely on
its behaviour about preferring src modules to package modules.

Duncan




More information about the cabal-devel mailing list