Telling cabal where the main module is
Asked Answered
T

2

10

I have a project with this structure:

foo.cabal
src/
    Foo/
        Main.hs

and part of foo.cabal looks like this:

executable foo
  main-is:             Foo/Main.hs
  hs-source-dirs:      src

Main.hs has the package name Foo.Main. When I build it cabal compiles everything but doesn't create an executable because it says there is no main module.

Warning: output was redirected with -o, but no output will be generated
because there is no Main module.

What am I doing wrong?

[EDIT] If I move Main up a level and change foo.cabal to read main-is: Main.hs it works. So can I not have a nested module name for Main?

Tannin answered 21/12, 2014 at 16:19 Comment(0)
E
11

The Main module must be called Main, not Foo.Main or anything else. If you want Foo.Main, then rename main in it to something like defaultMain, then make a top level Main module that imports Foo.Main (defaultMain) and defines main = defaultMain, such as:

src/
    Foo/
        Main.hs
    Main.hs
foo.cabal

Where

-- src/Foo/Main.hs
module Foo.Main
    ( defaultMain
    ) where

defaultMain :: IO ()
defaultMain = putStrLn "Hello, world!"

And

-- src/Main.hs
module Main where

import Foo.Main (defaultMain)

main :: IO ()
main = defaultMain

Alternatively, you could keep it Foo.Main.main and just import it qualified.

Encrust answered 21/12, 2014 at 16:29 Comment(3)
Every complete Haskell program must define main in module Main in package main.Embolic
if the module exports a main, you can write just module Main where import Foo.Main (main) (with or without explicit importing of mainInlaid
@maxtaldykin That's not been true for GHC since at least the mid-2000s (I was using -main-is around 2006), but the documentation has never been corrected. See the -main-is thing" documentation in 4.12.6. Options affecting linking and my answer below.Spock
S
3

Cabal's main-is: specifies only the filename from which to build the module containing the entrypoint (default Main.main); it does not allow changing that default.

Changing the default is compiler-specific, but if you are using GHC you can do this by passing a compiler command-line option: to your Cabal file executable definition add ghc-options: -main-is Foo. You may also use a different top-level function as the entry point: ghc-options: Foo.startup for example. See -main-is <thing> in the documentation for more details.

If you're using a package.yaml (as used by hpack/Stack/etc.) you may specify for main: either:

  1. A .hs filename, in which case that will be directly used on the main-is: line in the generated Cabal file; or
  2. A module name or module and exported definition name (e.g., Foo or Foo.startup) in which case the appropriate ghc-options: -main-is ... will be added to the generated Cabal file and main-is: will be a filename generated from the module name (e.g. main-is: Foo.hs).
Spock answered 26/1, 2022 at 0:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.