2012-09-06 12 views
53

Wenn Sie declare a library + executable sections in a cabal file while avoiding double compilation of the library, indem Sie die Bibliothek in ein Verzeichnis hs-source-dirs setzen, können Sie in der Regel Ihr Projekt mit ghci und runhaskell nicht mehr ausführen, vor allem, wenn die ausführbaren Dateien Helper-Module selbst haben.Wie macht man ein Haskell-Cabal-Projekt mit Bibliothek + ausführbaren Dateien, die noch mit runhaskell/ghci laufen?

Was ist ein empfehlenswertes Projekt-Layout, dass

  • baut nur das, was einmal benötigt
  • runhaskell mit ermöglicht
  • eine saubere Struktur ohne Hacks hat?

Antwort

84

Nehmen wir an, Sie eine mylib Bibliothek haben, und mylib-commandline und mylib-server ausführbare Dateien.

Sie verwenden hs-source-dirs für die Bibliothek und jede ausführbare Datei, so dass jede ihr eigenes Projekt Wurzel hat, doppelte Kompilation zu vermeiden:

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 

Vollverzeichnisstruktur:

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 

Der zapfenförmige Einstiegspunkt Datei mylib-commandline/Main.hs sieht so aus:

module Main where 

import qualified Web.Mylib.Server.Main as MylibServer 

main :: IO() 
main = MylibServer.main 

Sie benötigen sie, weil ein executable auf einem Modul mit dem Namen Main gestartet werden muss.

Ihre mylib.cabal sieht wie folgt aus:

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 wird die Bibliothek und die beiden ausführbaren Dateien ohne doppelte Erstellung der Bibliothek bauen, weil jede in ihrem eigenen hs-source-dirs ist und die ausführbaren Dateien hängen von der Bibliothek.

Sie können immer noch die ausführbaren Dateien mit runghc aus dem Projekt root ausführen, mit dem -i Schalter zu sagen, wo es für die Module aussehen soll (mit : als Trennzeichen):

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

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

Auf diese Weise können Sie eine haben sauberes Layout, ausführbare Dateien mit Hilfsmodulen, und alles funktioniert immer noch mit runhaskell/runghc und ghci. Zur Vermeidung dieses Flag Eingabe wiederholt, können Sie etwas Ähnliches wie

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

auf Ihre .ghci Datei hinzufügen.


Beachten Sie, dass manchmal Ihren Code in separate Pakete, z. mylib, mylib-commandline und mylib-server.

+0

Perfekte Antwort, ich war auf der Suche nach solchen einfachen und geradlinigen Artikel auf offiziellen Haskell Pages, aber ohne Glück. Wahrscheinlich habe ich nicht genug Zeit mit der Suche verbracht, aber das hat mir sehr geholfen. Vielen Dank! – korCZis

3

Sie können cabal repl verwenden, um ghci mit der Konfiguration aus der cabal-Datei und cabal run zu starten, um die ausführbaren Dateien zu kompilieren und auszuführen.Im Gegensatz zu runhaskell und ghci greift die Verwendung von cabal repl und cabal run auch Abhängigkeiten von cabal-Sandboxes korrekt auf.

Verwandte Themen