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

nh2*_*nh2 54 haskell ghci cabal runhaskell

如果你在一个小集团文件中声明库+可执行部分,而避免了图书馆的双重编译通过把图书馆变成一个hs-source-dirs目录下,你不能用通常运行项目ghcirunhaskell了,特别是如果可执行文件有辅助模块本身.

什么是推荐的项目布局

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

nh2*_*nh2 86

假设您有一个mylibmylib-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
Run Code Online (Sandbox Code Playgroud)

完整目录布局:

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
Run Code Online (Sandbox Code Playgroud)

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

module Main where

import qualified Web.Mylib.Server.Main as MylibServer

main :: IO ()
main = MylibServer.main
Run Code Online (Sandbox Code Playgroud)

你需要它们,因为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]
Run Code Online (Sandbox Code Playgroud)

cabal build将构建库和两个可执行文件而无需对库进行双重编译,因为每个库都是自己的hs-source-dirs,可执行文件依赖于库.

您仍然可以runghc从项目根目录运行可执行文件,使用-i开关告诉它应该在哪里查找模块(使用:作为分隔符):

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

runhaskell -isrc:mylib-server mylib-server/Server.hs
Run Code Online (Sandbox Code Playgroud)

这样,您可以拥有一个干净的布局,带有辅助模块的可执行文件,并且所有内容仍然适用于runhaskell/ runghcghci.为避免重复键入此标志,您可以添加类似的内容

:set -isrc:mylib-commandline:mylib-server
Run Code Online (Sandbox Code Playgroud)

到你的.ghci文件.


请注意,有时应该分裂您的代码到单独的包,如mylib,mylib-commandlinemylib-server.