本文介绍了如何用库+可执行文件构建一个Haskell cabal项目,该项目仍然可以通过runhaskell / ghci运行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果您,将库放入 hs-source-dirs 目录中,通常不能使用 ghci runhaskell ,特别是如果可执行文件本身有辅助模块的话。



什么是推荐的项目布局




  • 只会构建一次所需的内容

  • 允许使用 runhaskell

  • 有干净的结构,没有黑客? h2_lin>解决方案

假设您有一个 mylib 库,并且 mylib-commandline mylib-server 可执行文件。



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

  mylib /#项目根目录
mylib.cabal
src /#根目录该库
tests /
mylib-commandline /#命令行实用程序的辅助工具+辅助程序模块
mylib-server /#Web服务+辅助程序模块的根目录


$ b

完整的目录布局:

  mylib /#项目根目录
mylib.cabal
src /#库的根目录
Web /
Mylib.hs#主库模块
Mylib /
ModuleA#Mylib.ModuleA
ModuleB#Mylib.ModuleB
tests /
...
mylib-commandline /#命令行实用程序的根目录
Main.hs# 模块主要在哪里存根main = Web.Mylib.Commandline.Main.main
Web /
Mylib /
命令行/
Main.hs#CLI入口点
Arguments.hs#程序命令行参数解析器
mylib-server /#Web服务的根目录
Server.hs#module Main stub withmain = Web.Mylib.Server.Main.main
Web /
Mylib /
服务器/
Main.hs#服务器入口点
参数.hs#服务器命令行参数解析器

入口点文件 mylib-commandline / Main.hs 看起来像这样:

  module主要在

中导入限定的Web.Mylib.Server.Main作为MylibServer

main :: IO()
main = MylibServer.main

您需要它们是因为可执行文件必须在一个简单的 Main



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

  library 
hs-source-dirs:src
exposed-modules:
Web.Mylib
Web.Mylib.ModuleA
Web.Mylib.ModuleB
build-depends:
base> = 4&& < = 5
,[库的其他依赖关系]

可执行mylib-commandline
hs-source-dirs:mylib-commandline
main-is:Main .hs
other-modules:
Web.Mylib.Commandline.Main
Web.Mylib.Commandline.Arguments
build-depends:
ase> = 4& amp ;&安培; < = 5
,mylib
,[CLI的其他依赖性]

可执行文件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
,[服务器的其他依赖关系]



$ cabal 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中。为避免重复输入此标志,可以添加类似于

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

添加到您的 .ghci 文件中。






请注意,有时应该将您的代码拆分为不同的包,例如 mylib mylib-commandline mylib-server


If you declare a library + executable sections in a cabal file while avoiding double compilation of the library by putting the library into a hs-source-dirs directory, you cannot usually run your project with ghci and runhaskell anymore, especially if the executables have helper modules themselves.

What is a recommended project layout that

  • only builds what is needed once
  • allows using runhaskell
  • has a clean structure without hacks?

解决方案

Let's assume you have a mylib library, and mylib-commandline and mylib-server executables.

You use hs-source-dirs for the library and each executable so that each has their own project root, avoiding double compilation:

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

Full directory layout:

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

The stub-like entry point file mylib-commandline/Main.hs looks like this:

module Main where

import qualified Web.Mylib.Server.Main as MylibServer

main :: IO ()
main = MylibServer.main

You need them because an executable must start on a module simply called Main.

Your mylib.cabal looks like this:

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 will build the library and the two executables without double compilation of the library, because each is in their own hs-source-dirs and the executables depend on the library.

You can still run the executables with runghc from your project root, using the -i switch to tell where it shall look for modules (using : as separator):

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

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

This way, you can have a clean layout, executables with helper modules, and everything still works with runhaskell/runghc and ghci. To avoid typing this flag repeatedly, you can add something similar to

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

to your .ghci file.


Note that sometimes should split your code into separate packages, e.g. mylib, mylib-commandline and mylib-server.

这篇关于如何用库+可执行文件构建一个Haskell cabal项目,该项目仍然可以通过runhaskell / ghci运行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-19 07:02