2012-09-06 18 views
53

Si declare a library + executable sections in a cabal file while avoiding double compilation of the library coloca la biblioteca en un directorio hs-source-dirs, normalmente no puede ejecutar su proyecto con ghci y runhaskell, especialmente si los archivos ejecutables tienen módulos auxiliares.¿Cómo hacer un proyecto Cabal de Haskell con biblioteca + ejecutables que aún se ejecutan con runhaskell/ghci?

Qué es un diseño de proyecto recomendado que

  • sólo construye lo que se necesita una vez
  • permite el uso de runhaskell
  • tiene una estructura limpia y sin cortes?

Respuesta

84

Supongamos que usted tiene una biblioteca mylib, y mylib-commandline y mylib-server ejecutables.

Usted utilizar hs-source-dirs para la biblioteca y cada ejecutable de manera que cada uno tiene su propia raíz del proyecto, evitando la doble compilación:

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 

disposición de directorios completo:

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 

El trozo similar a archivo de punto de entrada mylib-commandline/Main.hs tiene este aspecto:

module Main where 

import qualified Web.Mylib.Server.Main as MylibServer 

main :: IO() 
main = MylibServer.main 

Los necesita porque un executable debe comenzar en un módulo llamado simplemente Main.

Su mylib.cabal se parece a esto:

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 construirá la biblioteca y los dos ejecutables sin doble compilación de la biblioteca, porque cada uno es en su propio hs-source-dirs y los ejecutables dependen de la biblioteca.

Todavía se puede ejecutar los archivos ejecutables con runghc desde su raíz del proyecto, con el interruptor -i decir de dónde deberá buscar módulos (utilizando : como separador):

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

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

De esta manera, se puede tener una diseño limpio, ejecutables con módulos auxiliares, y todo sigue funcionando con runhaskell/runghc y ghci. Para evitar tener que escribir esta bandera en repetidas ocasiones, se puede añadir algo similar a

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

a su archivo .ghci.


Tenga en cuenta que a veces se debe dividir el código en paquetes separados, p. mylib, mylib-commandline y mylib-server.

+0

Respuesta perfecta, estaba buscando un artículo simple y sencillo en las páginas oficiales de Haskell, pero sin suerte. Probablemente no pasé suficiente tiempo buscando pero esto me ayudó mucho. ¡Gracias! – korCZis

3

Puede usar cabal repl para iniciar ghci con la configuración desde el archivo cabal y cabal run para compilar y ejecutar los archivos ejecutables.A diferencia de runhaskell y ghci, al usar cabal repl y cabal run también se recogen las dependencias de los cajones de arena de cabal correctamente.

Cuestiones relacionadas