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

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

什么是推荐的项目布局

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

假设您有一个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 >= XX , [other dependencies for the server] 

cabal build将build立库和两个可执行文件,而不需要对库进行双重编译,因为每个文件都在自己的hs-source-dirs ,而且可执行文件依赖于库。

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

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

这样,你可以有一个干净的布局,带有辅助模块的可执行文件,并且一切仍然可以与runhaskell / runghcghci 。 为了避免重复input这个标志,你可以添加类似的东西

 :set -isrc:mylib-commandline:mylib-server 

到您的.ghci文件。


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

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