56

如果您在 cabal 文件中声明一个库 + 可执行部分,同时通过将库放入一个hs-source-dirs目录来避免库的双重编译,您通常不能再使用ghciand运行您的项目runhaskell,特别是如果可执行文件本身具有帮助模块。

什么是推荐的项目布局

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

2 回答 2

89

假设您有一个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

完整目录布局:

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文件。


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

于 2012-09-06T18:12:13.650 回答
3

您可以使用cabal replcabal 文件中的配置启动 ghci,并cabal run编译和运行可执行文件。与runhaskelland不同ghci,使用cabal replandcabal run还可以正确地从 cabal 沙箱中获取依赖项。

于 2015-03-19T08:10:53.803 回答