Comment faire un projet Haskell Cabal avec library + exécutables qui fonctionnent toujours avec runhaskell / ghci?

Si vous déclarez une bibliothèque + des sections exécutables dans un fichier cabal tout en évitant la double compilation de la bibliothèque en plaçant la bibliothèque dans un répertoire hs-source-dirs , vous ne pouvez plus exécuter votre projet avec ghci et runhaskell , surtout si les exécutables ont une aide modules eux-mêmes.

Quelle est la présentation du projet recommandée?

  • ne construit que ce qui est nécessaire une fois
  • permet d’utiliser runhaskell
  • a une structure propre sans hacks?

Supposons que vous ayez une bibliothèque mylib-commandline et mylib-server exécutables mylib-server et mylib-server .

Vous utilisez hs-source-dirs pour la bibliothèque et chaque exécutable afin que chacun ait sa propre racine de projet, en évitant la 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 

Disposition complète du répertoire:

 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 

Le fichier de point d’entrée de type stub mylib-commandline/Main.hs ressemble à ceci:

 module Main where import qualified Web.Mylib.Server.Main as MylibServer main :: IO () main = MylibServer.main 

Vous en avez besoin car un executable doit démarrer sur un module appelé simplement Main .

Votre mylib.cabal ressemble à ceci:

 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 va construire la bibliothèque et les deux exécutables sans double compilation de la bibliothèque, car chacun se trouve dans leurs propres hs-source-dirs et les exécutables dépendent de la bibliothèque.

Vous pouvez toujours exécuter les exécutables avec runghc depuis la racine de votre projet, en utilisant le commutateur -i pour indiquer où rechercher les modules (en utilisant : comme séparateur):

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

De cette façon, vous pouvez avoir une mise en page propre, des exécutables avec des modules d’aide, et tout fonctionne toujours avec runhaskell / runghc et ghci . Pour éviter de taper cet indicateur à plusieurs resockets, vous pouvez append quelque chose de similaire à

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

à votre fichier .ghci .


Notez que vous devez parfois diviser votre code en paquets distincts, par exemple mylib , mylib-commandline mylib-server et mylib-server .

Vous pouvez utiliser cabal repl pour démarrer ghci avec la configuration du fichier cabal run et de la commande cabal run pour comstackr et exécuter les exécutables. À la différence de runhaskell et ghci , l’utilisation de cabal repl et de cabal run également de détecter correctement les dépendances des sandbox de Cabal.