Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create binary distributions of applications with cabal (the tool) or stack

I've written an application in Haskell and it's starting to become slightly useful to users. However my application isn't targeted at technically adept folks, let alone Haskell developers, so building my application from source isn't really something I can expect them to do.

So to make my application available to my users, I would like build the application myself, put its executable, data files, dependencies, the dependencies' data files, required licensing information and other required files into one archive and put that archive up onto a website. Now users can download that archive, unpack it and have everything required to run my application.

The process I described above seems like a fairly common way to distribute binaries of applications to me. However, I can't figure out what tools to use or how to configure them to build my application into a binary distribution described above.

Cabal (the library) seems to have the features that are required for this. Usual Setup.hs scripts (without cabal (the tool) or stack as wrappers) support options such as --prefix and --enable-relocatable that let you install a package to the given prefix and compile them in such a way as to ensure that data files can still be located if the prefix (as a whole) is moved somewhere else.

But using the raw Setup.hs has the downside that it doesn't handle automatically installing dependencies. And since many decently sized Haskell applications will have hundreds of dependencies (or at least mine does), configuring and building each of them by hand isn't really feasible.

The obvious solution to the problem of installing dependencies would be to use a wrapper tool such as cabal (the tool) or stack, since they are specifically made to deal with the problem of large dependency trees. However, they all seem to have problems preventing me from building my application as a binary distribution:

  • stack build doesn't have the options --prefix or --enable-relocatable and instead always installs to .stack-work and ~/.stack.

  • cabal v2-* has the options --prefix and --enable-relocatable but seems to ignore them entirely and instead always installs to dist-newstyle and ~/.cabal.

  • cabal v1-* seems to do what I want for very simple cases. However, for more complicated cases it produces obscure build failures, where GHC complains about not finding modules from dependencies and cabal complains about partially installed packages. But even putting these failures aside, using legacy commands for a new workflow doesn't seems like a good idea in general.

So, since I seem to be out of luck with these tools, what other tools can i use to build Haskell applications into binary distributions? Or maybe one of the tools I listed actually does what I want and I'm just using it the wrong way?

Some limitations in scope:

  • For now I'm mostly interested in builds for Windows, but solutions for other platforms would be interesting as well.
  • When I'm talking about dependencies, I mostly mean Haskell dependencies (i.e. Cabal packages). Solutions which also bundle foreign C dependencies would be interesting, but that's not a strict requirement.
like image 474
Kritzefitz Avatar asked Aug 12 '21 17:08

Kritzefitz


People also ask

How do I create a cabal project?

To create a new project using Cabal, you should first be in a specific directory set aside for the project. Then you can use cabal init -n to create a project. This will auto-generate a . cabal file for you with defaults in all the metadata fields.

What is stack Haskell?

Stack's functions Stack handles the management of your toolchain (including GHC — the Glasgow Haskell Compiler — and, for Windows users, MSYS2), building and registering libraries, building build tool dependencies, and more.

Where does stack install packages?

Stack installs the Stackage libraries in ~/. stack and any project libraries or extra dependencies in a . stack-work directory within each project's directory.


1 Answers

A workaround is to use cabal repl like this (from the directory with your-package.cabal):

$ cabal repl -b Cabal
...
ghci> :load /path/to/Setup.hs
...
ghci> :main configure --prefix=/my/prefix
...
ghci> :main build
...
ghci> :main copy --destdir=/my/dest/dir
...

That should take care of building all your dependencies, while still being able to use Setup.hs.

I think this can still cause issues if your dependencies use data-files.

like image 78
Noughtmare Avatar answered Nov 15 '22 06:11

Noughtmare