If you declare a library + executable sections in a cabal file while avoiding double compilation of the library by putting the library into a hs-source-dirs directory, you cannot usually run your project with ghci and runhaskell anymore, especially if the executables have helper modules themselves.
What is a recommended project layout that
runhaskell Let's assume you have a mylib library, and mylib-commandline and mylib-server executables.
You use hs-source-dirs for the library and each executable so that each has their own project root, avoiding double compilation:
mylib/ # Project root mylib.cabal src/ # Root for the library tests/ mylib-commandline/ # Root for the command line utility + helper modules mylib-server/ # Root for the web service + helper modules Full directory layout:
mylib/ # Project root mylib.cabal src/ # Root for the library Web/ Mylib.hs # Main library module Mylib/ ModuleA # Mylib.ModuleA ModuleB # Mylib.ModuleB tests/ ... mylib-commandline/ # Root for the command line utility Main.hs # "module Main where" stub with "main = Web.Mylib.Commandline.Main.main" Web/ Mylib/ Commandline/ Main.hs # CLI entry point Arguments.hs # Programm command line arguments parser mylib-server/ # Root for the web service Server.hs # "module Main where" stub with "main = Web.Mylib.Server.Main.main" Web/ Mylib/ Server/ Main.hs # Server entry point Arguments.hs # Server command line arguments parser The stub-like entry point file mylib-commandline/Main.hs looks like this:
module Main where import qualified Web.Mylib.Server.Main as MylibServer main :: IO () main = MylibServer.main You need them because an executable must start on a module simply called Main.
Your mylib.cabal looks like this:
library hs-source-dirs: src exposed-modules: Web.Mylib Web.Mylib.ModuleA Web.Mylib.ModuleB build-depends: base >= 4 && <= 5 , [other dependencies of the library] executable mylib-commandline hs-source-dirs: mylib-commandline main-is: Main.hs other-modules: Web.Mylib.Commandline.Main Web.Mylib.Commandline.Arguments build-depends: base >= 4 && <= 5 , mylib , [other depencencies for the CLI] executable mylib-server hs-source-dirs: mylib-server main-is: Server.hs other-modules: Web.Mylib.Server.Main build-depends: base >= 4 && <= 5 , mylib , warp >= X.X , [other dependencies for the server] cabal build will build the library and the two executables without double compilation of the library, because each is in their own hs-source-dirs and the executables depend on the library.
You can still run the executables with runghc from your project root, using the -i switch to tell where it shall look for modules (using : as separator):
runhaskell -isrc:mylib-commandline mylib-commandline/Main.hs runhaskell -isrc:mylib-server mylib-server/Server.hs This way, you can have a clean layout, executables with helper modules, and everything still works with runhaskell/runghc and ghci. To avoid typing this flag repeatedly, you can add something similar to
:set -isrc:mylib-commandline:mylib-server to your .ghci file.
Note that sometimes should split your code into separate packages, e.g. mylib, mylib-commandline and mylib-server.
You can use cabal repl to start ghci with the configuration from the cabal file and cabal run to compile and run the executables. Unlike runhaskell and ghci, using cabal repl and cabal run also picks up dependencies from cabal sandboxes correctly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With