4

I have two files in app folder

app/
|-- Main.hs
|-- SomeFunc2.hs

The SomeFunc2.hs is just to print a different string

module SomeFunc2 where

import Lib

main :: IO ()
main = putStrLn "someFunc2"

When I define multiple executables in package.yaml like this

executables:
  multiexes-exe:
    main:                Main.hs
    source-dirs:         app
    ghc-options:
    - -threaded
    - -rtsopts
    - -with-rtsopts=-N
    dependencies:
    - multiexes

  somefunc2-exe:
    main:                SomeFunc2.hs
    source-dirs:         app
    ghc-options:
    - -threaded
    - -rtsopts
    - -with-rtsopts=-N
    dependencies:
    - multiexes

I got error:

▸ stack build
Building all executables for `multiexes' once. After a successful build of all of them, only specified executables will be rebuilt.
multiexes-0.1.0.0: configure (lib + exe)
Configuring multiexes-0.1.0.0...
multiexes-0.1.0.0: build (lib + exe)
Preprocessing library for multiexes-0.1.0.0..
Building library for multiexes-0.1.0.0..
[2 of 2] Compiling Lib              ( src/Lib.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/Lib.o )
Preprocessing executable 'multiexes-exe' for multiexes-0.1.0.0..
Building executable 'multiexes-exe' for multiexes-0.1.0.0..
[1 of 3] Compiling Main             ( app/Main.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/multiexes-exe/multiexes-exe-tmp/Main.o ) [Lib changed]
[3 of 3] Compiling SomeFunc2        ( app/SomeFunc2.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/multiexes-exe/multiexes-exe-tmp/SomeFunc2.o )
Linking .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/multiexes-exe/multiexes-exe ...
Preprocessing executable 'somefunc2-exe' for multiexes-0.1.0.0..
Building executable 'somefunc2-exe' for multiexes-0.1.0.0..
Warning: Enabling workaround for Main module 'Main' listed in 'other-modules'
illegaly!
[1 of 2] Compiling Paths_multiexes  ( .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/somefunc2-exe/autogen/Paths_multiexes.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/somefunc2-exe/somefunc2-exe-tmp/Paths_multiexes.o )
[2 of 2] Compiling SomeFunc2        ( app/SomeFunc2.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/somefunc2-exe/somefunc2-exe-tmp/SomeFunc2.o )

<no location info>: error:
    output was redirected with -o, but no output will be generated
because there is no Main module.


--  While building custom Setup.hs for package multiexes-0.1.0.0 using:
      /Users/leo/.stack/setup-exe-cache/x86_64-osx/Cabal-simple_mPHDZzAJ_2.0.1.0_ghc-8.2.2 --builddir=.stack-work/dist/x86_64-osx/Cabal-2.0.1.0 build lib:multiexes exe:multiexes-exe exe:somefunc2-exe --ghc-options " -ddump-hi -ddump-to-file -fdiagnostics-color=always"
    Process exited with code: ExitFailure 1

How to fix it? Thanks!

Leo Zhang
  • 3,040
  • 3
  • 24
  • 38

2 Answers2

7

Found a solution, if I create a folder for each executable and have a Main.hs in each folder, then it works.

app/
|-- Main.hs
somefunc2/
|-- Main.hs

In package.yaml, change the source-dirs to be those folders:

executables:
  multiexes-exe:
    main:                Main.hs
    source-dirs:         app
    ghc-options:
    - -threaded
    - -rtsopts
    - -with-rtsopts=-N
    dependencies:
    - multiexes

  somefunc2-exe:
    main:                Main.hs
    source-dirs:         somefunc2
    ghc-options:
    - -threaded
    - -rtsopts
    - -with-rtsopts=-N
    dependencies:
    - multiexes
Leo Zhang
  • 3,040
  • 3
  • 24
  • 38
1

The module that contains the main function and is supposed to become an executable must be named Main, as in

module Main (main) where

You can also omit the module declaration altogether to the same effect. Your problem is in

module SomeFunc2 where

This convention is specified in the Haskell report, and while GHC allows to change the module name containing main, Cabal does not.

To quote from the last link:

Further, while the name of the file may vary, the module itself must be named Main.

So in this case it's fine to name the module Main (or omit the module name declaration) even though the file itself is not called Main.hs.

Roman Cheplyaka
  • 37,738
  • 7
  • 72
  • 121
  • Then the answer is impossible? I can't rename `SomeFunc2` to `Main`, because there is `Main.hs` exist already. But if I can't define multiple executables in `packages.yaml`, then it doesn't make sense that the section is called executable`s`, which sounds as if it supported multiple executables. – Leo Zhang Jun 12 '18 at 19:45
  • It is possible; I updated the answer to make it more clear. Also, if you really want to name both files `Main.hs`, you could place them in different directories (different `source-dirs`). – Roman Cheplyaka Jun 12 '18 at 20:09
  • 1
    No. It doesn't work. If I change the `SomeFunc2.hs` to be `module Main where`, I get the following error: File name does not match module name: Saw: ‘Main’ Expected: ‘SomeFunc2’ | 1 | module Main where – Leo Zhang Jun 12 '18 at 21:33