Как создать Cabal-проект на Haskell с библиотекой + исполняемыми файлами, которые по-прежнему работают с runhaskell/ghci?

Если вы объявите библиотеку + исполняемые разделы в файле cabal, избегая двойной компиляции библиотеки, поместив библиотеку в hs-source-dirs каталог, вы обычно не можете запустить свой проект с ghci а также runhaskell больше, особенно если исполняемые файлы сами имеют вспомогательные модули.

Каков рекомендуемый макет проекта, который

  • строит только то, что нужно один раз
  • позволяет использовать runhaskell
  • имеет чистую структуру без взломов?

2 ответа

Решение

Давайте предположим, что у вас есть 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 >= 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/runghc а также ghci, Чтобы не вводить этот флаг несколько раз, вы можете добавить что-то похожее на

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

на ваш .ghci файл.


Обратите внимание, что иногда следует разбить ваш код на отдельные пакеты, например mylib, mylib-commandline а также mylib-server,

Ты можешь использовать cabal repl запустить ghci с конфигурацией из файла cabal и cabal run скомпилировать и запустить исполняемые файлы. В отличие от runhaskell а также ghci, с помощью cabal repl а также cabal run также правильно подбирает зависимости из песочницы клики.

Другие вопросы по тегам