如何使用仍然使用runhaskell / ghci运行的库+可执行文件来创建Haskell cabal项目?

时间:2012-09-06 18:12:14

标签: haskell cabal ghci runhaskell

如果您declare a library + executable sections in a cabal file while avoiding double compilation of the library将库放入hs-source-dirs目录,则通常不能再使用ghcirunhaskell运行项目,尤其是在可执行文件具有帮助程序模块的情况下自己。

推荐的项目布局是什么

  • 只构建一次所需的内容
  • 允许使用runhaskell
  • 有一个没有黑客的干净结构?

2 个答案:

答案 0 :(得分:86)

假设您有一个mylib库,以及mylib-commandlinemylib-server个可执行文件。

您使用hs-source-dirs作为库和每个可执行文件,以便每个都有自己的项目根目录,避免双重编译:

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

完整目录布局:

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

类存根入口点文件mylib-commandline/Main.hs如下所示:

module Main where

import qualified Web.Mylib.Server.Main as MylibServer

main :: IO ()
main = MylibServer.main

您需要它们,因为executable必须从名为Main的模块开始。

您的mylib.cabal看起来像这样:

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将构建库和两个可执行文件而无需对库进行双重编译,因为每个库都在自己的hs-source-dirs中,可执行文件依赖于库。

您仍然可以使用runghc开关从项目根目录运行带有-i的可执行文件,以告知模块的位置(使用:作为分隔符):

runhaskell -isrc:mylib-commandline mylib-commandline/Main.hs

runhaskell -isrc:mylib-server mylib-server/Server.hs

通过这种方式,您可以拥有干净的布局,包含帮助程序模块的可执行文件,并且所有内容仍然适用于runhaskell / runghcghci。为避免重复输入此标志,您可以添加类似于

的内容
:set -isrc:mylib-commandline:mylib-server

到您的.ghci文件。


请注意,有时应将您的代码拆分为单独的包,例如mylibmylib-commandlinemylib-server

答案 1 :(得分:3)

您可以使用cabal repl使用cabal文件和cabal run中的配置启动ghci来编译和运行可执行文件。与runhaskellghci不同,使用cabal replcabal run也可以正确地从cabal沙箱中获取依赖关系。