24

With the following project structure:

src/FirstExecutable.hs
src/SecondExecutable.hs
my-amazing-project.cabal

and the following cabal setup:

name:               my-amazing-project
version:            0.1.0.0
build-type:         Simple
cabal-version:      >=1.8

executable first-executable
  hs-source-dirs:   src
  main-is:          FirstExecutable.hs
  ghc-options:      -O2 -threaded -with-rtsopts=-N
  build-depends:    base == 4.5.*

executable second-executable
  hs-source-dirs:   src
  main-is:          SecondExecutable.hs
  ghc-options:      -O2 -threaded -with-rtsopts=-N
  build-depends:    base == 4.5.*

Running cabal install fails with the following output:

Installing executable(s) in
/Users/mojojojo/Library/Haskell/ghc-7.4.2/lib/my-amazing-project-0.1.0.0/bin
cabal: dist/build/second-executable/second-executable: does not exist
Failed to install my-amazing-project-0.1.0.0
cabal: Error: some packages failed to install:
my-amazing-project-0.1.0.0 failed during the final install step. The exception
was:
ExitFailure 1

What am I doing wrong or is this a Cabal bug?


The contents of the executable modules are as follows:

module FirstExecutable where

main = putStrLn "Running FirstExecutable"

and

module SecondExecutable where

main = putStrLn "Running SecondExecutable"
Nikita Volkov
  • 42,792
  • 11
  • 94
  • 169

1 Answers1

30

cabal expects the module of the executable to be Main. You should skip the module line or use module Main where.

Ok here is the possible reason. The executable of a haskell program is not produced when the module is not Main when you actually compile the program. The main function of the Main module is used when the executable is run. A possible workaround for ghc is -main-is flag. So you can have something like

name:               my-amazing-project
version:            0.1.0.0
build-type:         Simple
cabal-version:      >=1.8

executable first-executable
  hs-source-dirs:   src
  main-is:          FirstExecutable.hs
  ghc-options:      -O2 -threaded -with-rtsopts=-N -main-is FirstExecutable
  build-depends:    base == 4.5.*

executable second-executable
  hs-source-dirs:   src
  main-is:          SecondExecutable.hs
  ghc-options:      -O2 -threaded -with-rtsopts=-N -main-is SecondExecutable
  build-depends:    base == 4.5.*
Satvik
  • 11,238
  • 1
  • 38
  • 46
  • 1
    Yes, that's exactly what I've just found out by accident after spending a few hours on googling and beating myself around. Quite frankly I'm frustrated with why they chose such a confusing behaviour. An awful design decision IMO – Nikita Volkov Jan 09 '13 at 16:02
  • 4
    @NikitaVolkov This behaviour is mandated by the [language standard](http://www.haskell.org/onlinereport/modules.html) - "A Haskell program is a collection of modules, one of which, by convention, must be called Main and must export the value main.". – Mikhail Glushenkov Jan 09 '13 at 16:04
  • @NikitaVolkov You can see the possible workaround I have suggested in the updated answer. – Satvik Jan 09 '13 at 16:07
  • 3
    @MikhailGlushenkov Thank you. So, Cabal guys go against the standard by allowing the user to declare "Main" modules named differently. Things like that should be noted boldly in the documentation, yet [there's not a word about this nor the actual issue in it](http://www.haskell.org/cabal/users-guide/developing-packages.html#executables). *(If somebody with access to it is reading this comment please take a notice).* – Nikita Volkov Jan 09 '13 at 16:17
  • 1
    @NikitaVolkov `-main-is` is a GHC extension. It's described [in the GHC documentation](http://www.haskell.org/ghc/docs/latest/html/users_guide/options-phases.html#options-linker). – Mikhail Glushenkov Jan 09 '13 at 16:53
  • 4
    Cabal's `main-is` and GHC's `-main-is` do different things. Cabal's `main-is` just lets you define the *filename* where the main module is located but the *module name* still has to be `Main` (i.e. the module declaration inside the file). GHC's `-main-is` allows the module name or the `main` function name to be something else. – shang Jan 10 '13 at 08:04