Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Building multiple executables in the default Haskell Stack project

I used the default stack new to setup a project that has a server and a client as separate executables. I altered the package.yaml file in what seems like the right way (As of April 21, 2020 "There is no user guide") and added a new file to my app directory called Client.hs.

I got an error saying "Enabling workaround for Main module 'Main' listed in 'other-modules' illegally!"

How do I have stack build both the client and the server?

When I ran stack build I got:

[... clip ...]
Building executable 'ObjectServer' for ObjectServer-0.1.0.1..
[4 of 4] Compiling Client
Linking .stack-work\dist\29cc6475\build\ObjectServer\ObjectServer.exe ...
Warning: Enabling workaround for Main module 'Main' listed in 'other-modules'
illegally!
Preprocessing executable 'Client' for ObjectServer-0.1.0.1..
Building executable 'Client' for ObjectServer-0.1.0.1..
[3 of 3] Compiling Client

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


--  While building package ObjectServer-0.1.0.1 using:
      D:\HaskellStack\setup-exe-cache\x86_64-windows\Cabal-simple_Z6RU0evB_3.0.1.0_ghc-8.8.3.exe --builddir=.stack-work\dist\29cc6475 build lib:ObjectServer exe:Client exe:ObjectServer --ghc-options " -fdiagnostics-color=always"
    Process exited with code: ExitFailure 1

The relevant portion of package.yaml looks like this:

executables:
  ObjectServer:
    main:                Main.hs
    source-dirs:         app
    ghc-options:
    - -threaded
    - -rtsopts
    - -with-rtsopts=-N
    dependencies:
    - ObjectServer
  Client:
    main:                Client.hs
    source-dirs:         app
    ghc-options:
    - -threaded
    - -rtsopts
    - -with-rtsopts=-N
    dependencies:
    - ObjectServer
like image 703
John F. Miller Avatar asked Apr 23 '20 01:04

John F. Miller


People also ask

Should I use cabal or stack?

stack is unable to share the caches of extra-deps or git sources, whereas cabal treats everything equally and can share builds between projects . Both stack and cabal can be used to create reproducible builds, with a caveat: ghc is non-deterministic and can produce different binary outputs for the same input.

Does Haskell have a stack?

In fact, Haskell does have a stack which can overflow, but it's not the call stack you're familiar with from C. It is quite possible to write non-tail-recursive functions which infinitely recurse and will consume all available memory without hitting a limit on call depth.

What does stack build do?

Stack allows you to call out a specific component to be built, e.g. stack build mypackage:test:mytests will build the mytests component of the mypackage package. mytests must be a test suite component. We'll get into the details of the target syntax for how to select components in the next section.

What is stack Haskell?

Stack's functions Stack handles the management of your toolchain (including GHC — the Glasgow Haskell Compiler — and, for Windows users, MSYS2), building and registering libraries, building build tool dependencies, and more.


1 Answers

There are two problems here. First, the default value for other-modules in hpack is "all modules in source-dirs except main and modules mentioned in a when clause". If you look at the generated .cabal file, you'll see that as a result of this default, each executable has incorrectly included the other executable's module in its other-modules list. Second, the main setting gives the source file that contains the main module, but doesn't change the name of the module expected by GHC from Main to anything else. Therefore, that module still needs to be named module Main where ..., not module Client where..., unless you also, separately add a -main-is Client GHC option.

So, I would advise modifying Client.hs to make it the Main module:

-- in Client.hs
module Main where
...

and then specifying other-modules: [] explicitly for both executables:

executables:
  ObjectServer:
    main:                Main.hs
    other-modules:       []
    source-dirs:         app
    ghc-options:
    - -threaded
    - -rtsopts
    - -with-rtsopts=-N
    dependencies:
    - ObjectServer
  Client:
    main:                Client.hs
    other-modules:       []
    source-dirs:         app
    ghc-options:
    - -threaded
    - -rtsopts
    - -with-rtsopts=-N
    dependencies:
    - ObjectServer

That seems to work in my testing.

like image 157
K. A. Buhr Avatar answered Nov 03 '22 09:11

K. A. Buhr