如何使用仍然运行runhaskell / ghci的库+可执行文件来创build一个Haskell cabal项目?
如果你在一个cabal文件中声明一个库+可执行部分,同时通过把库放到一个hs-source-dirs
目录中来避免对库的双重编译 ,你通常不能再用ghci
和runhaskell
来运行你的项目,特别是如果可执行文件有帮助模块本身。
什么是推荐的项目布局
- 只build立一次需要的东西
- 允许使用
runhaskell
- 有没有黑客干净的结构?
假设您有一个mylib
库,以及mylib-commandline
和mylib-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
/ runghc
和ghci
。 为了避免重复input这个标志,你可以添加类似的东西
:set -isrc:mylib-commandline:mylib-server
到您的.ghci
文件。
请注意,有时应将代码拆分为单独的包,例如mylib
, mylib-commandline
和mylib-server
。
您可以使用cabal repl
通过cabal文件和cabal run
的configuration来启动ghci来编译和运行可执行文件。 与runhaskell
和ghci
不同的是,使用cabal repl
和cabal run
也能正确地从cabal沙箱中获得依赖关系。