In Haskell, while using stack, there are three places where we can define dependencies on the package.yaml
file; under library
and executables
. What is the difference between defining a dependency in these places and when should I use them?
CodePudding user response:
Let's say you want to build and application with two front ends: CLI and a GUI, both using the same underliying logic. Obviously, your CLI doesn't use any graphical libraries, so It shouldn't depend on them and viceversa. Your package.yaml
will look something like.
name: my-app
version: 0.1.0.0
# This are the dependencies all the components depends on.
dependencies:
- base >= 4.7 && < 5
# This is the description of your "common logic" i.e. the library
library:
source-dirs: src
# depends on whatever libraries of your choice
dependencies:
- bytestring
- megaparsec
- parser-combinators
- transformers
executables:
# The executable name for the cli
my-app-cli:
# The main function is in cli.hs
main: cli.hs
source-dirs: app
ghc-options:
- -Wall
- -Wextra
- -threaded
- -rtsopts
- -with-rtsopts=-qg
# It depends on you library, the base library (which remember is at the top of the file), and on whatever other libraries you use to build the cli, for example optparse-applicative
dependencies:
- my-app
- optparse-applicative
# The executable name for the GUI
my-app-gui:
# The main function is on gui.hs
main: gui.hs
source-dirs: app
ghc-options:
- -Wall
- -Wextra
- -threaded
- -rtsopts
- -with-rtsopts=-qg
# Again, It depends on your library, the base, and a GUI library of your choice. Example monomer.
dependencies:
- my-app
- monomer
Now when you run stack build
it will create two executables, one named my-app-cli
and other my-app-gui
, each with its own dependencies, but sharing the common ones. Ideally one could run stack build my-app:my-app-cli
to build just one of the executables, but for some reason stack
builds everything (which apparently is due to some cabal
behaviour... don't know, don't care)
That been said, I don't think this is different from other programming languages. For example, I tend to structure my Python
code the same way. A common library with its own requirements.txt
and then different applications each with its own requirement.txt
depending if the application is gonna be a web server, a machine learning model or what ever... this simplifies creating cached layer in docker for example. If I need to add some dependencies to the web server, they are added to the web server requirements.txt
instead of the library one. This is, of course opinionated but my point is that this isn't haskell specific.