How to check for haskell package versions in ./configure? - haskell

how can I tell configure to check for version >= x.y of a given Haskell package?
Thanks,

Use cabalvchk: http://hackage.haskell.org/package/cabalvchk-0.2
For example, to verify that the version of parsec is >= 0.4, you could issue:
$ cabalvchk parsec '>= 0.4'
The return code will be zero if the version constraint is satisfied and non-zero otherwise. The version constraint can be anything cabal understands. An optional third parameter can be non-blank to request verbose output.

I don't know much about configure; can you ask it to run a particular command? If so, then ghc-pkg latest should help you out. For example, here's a run on my machine for the zlib package:
% ghc-pkg latest zlib
zlib-0.5.3.1
% ghc-pkg latest --global zlib
zlib-0.5.3.1
% ghc-pkg latest --user zlib
ghc-pkg: cannot find package zlib
zsh: exit 1 ghc-pkg latest --user zlib
The --global should be used for system-wide installations, and no flag at all for user-specific installations. The --user flag should only be used when you want to check whether a user has a local installation of a package (that may override the global one).
Unless you have a reason not to, I recommend ditching configure in favor of cabal. For cabal, the solution here is to first cabal init in your project's directory, then check that you have a line like this in the .cabal file that's created:
build-depends: zlib >= 0.5
The cabal toolchain is the standard for Haskell projects (because it automates and simplifies many things, including dependency-chasing). You can also ask cabal to invoke configure if there are other dependencies. Open a separate question if you'd like more information about this.

Perhaps the better question is: should you? Checking for a specific version number is one of the great arguments in the autoconf world, and the general winner of the debate is the side which says you should never do it. What specific feature of Haskell do you need? Test for that. As a simple example (unrelated to haskell), suppose your program uses inotify so you want the configury to test if it is available. You could just test if the kernel version is > 2.6.13, but then when Joe tries to build your program on his 2.4.xx version in which he has patched in inotify capability, he's going to be really irritated that your program won't work.
You do not care if Haskell > x.y is available. Instead, there is some specific feature of Haskell that you want that was introduced in x.y; test for that feature.

Using ghc-pkg list, you can get a list of installed versions of a package in ascending order. You should hopefully be able to filter through this list looking for a match. (I don't know how to do this with configure, sorry).
$ ghc-pkg list yesod
/home/ahammar/.haskell/lib/ghc-7.0.2/package.conf.d
/home/ahammar/.ghc/x86_64-linux-7.0.2/package.conf.d
yesod-0.8.2.1
yesod-0.9.1
yesod-0.9.2.2

Try something like this:
# Find ghc-pkg, so we can do version checks
AC_ARG_VAR([GHC_PKG], [Path to ghc-pkg])
AC_PATH_PROG([GHC_PKG], [ghc-pkg])
AS_IF([test -z "$GHC_PKG"], [AC_MSG_ERROR([Cannot find ghc-pkg.])])
# Check that the package actually exists
AC_MSG_CHECKING([for Haskell package foo])
AS_IF([$GHC_PKG latest foo > /dev/null 2>&1],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
AC_MSG_ERROR([Cannot find foo])])
# Check its version
AC_MSG_CHECKING([if foo is new enough])
foo_ver=`$GHC_PKG latest foo | sed 's/^foo-//'`
# At this point you have the version of foo and the minimum version you want.
# The rest of the test is pretty easy to write, use cut and test to compare the
# version numbers. If it's new enough, AC_MSG_RESULT([yes]).
# If not, AC_MSG_RESULT([no]) and AC_MSG_ERROR([foo is not new enough.])

Related

Building the Spock tutorial example fails

I wanted to get going with Haskell a little bit and therefore took a look at the Spock framework. To start clean, I uninstalled everything Haskell related from my Arch Linux machine and installed ghcup, Cabal and Stack using the install scripts from their respective websites.
Now I want to follow Spock's Tutorial. Trying to install Spock globally with cabal install Spock as suggested gives me an error (abbreviated):
src/Web/Spock/Internal/Wire.hs:43:1: error:
Could not find module ‘Web.Routing.AbstractRouter’
Use -v (or `:set -v` in ghci) to see a list of the files searched for.
|
43 | import Web.Routing.AbstractRouter
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cabal: Failed to build Spock-0.9.0.1. See the build log above for details.
I already found a question on reddit on the topic, but the solution does not apply because I'm not trying to use a specific version of the libraries as implied.
So I try to follow along and build only locally.
But when I reach the point where it says stack build --fast --pedantic, the build plan can not be constructed and Stack suggests to add another dependency, stm-containers. Doing so, I am presented with two additional suggestions for focus and primitive. When I add these, the plan fails again, this time without a simple solution:
In the dependencies for primitive-0.6.4.0:
base-4.13.0.0 from stack configuration does not match >=4.5 && <4.13 (latest matching version is 4.12.0.0)
needed due to Spock-example-0.1.0.0 -> primitive-0.6.4.0
I can do a little thing with Haskell, but with the build system(s), I am way out of my comfort zone. Help and hints appreciated. Oh, and all versions of course are the latest by the time of this post.
Due to incompatible versions of dependencies, Spock won't build with GHC 8.8 and above. A similar problem is described in Spock issue #149, though I'm not fully sure it is exactly the same incompatibility. The error you got from Stack hints at that, as base-4.13.0.0 is the version of base that is bundled with GHC 8.8. cabal-install failed in a more obscure way because, upon noting the incompatibility, it tries to solve the dependencies using older versions of Spock, eventually picking 0.9.0.1, attempting and, thanks to a missing version upper bound for the reroute dependency, failing to build it.
(Shortly after this answer was posted, the missing upper bound was retrofitted to the old Spock version, so attempting to reproduce the problem now will lead to an easier to understand failure.)
Casting the tutorial aside, the most straightforward way to use Spock given those complications is probably through cabal-install 3+. Begin by using ghcup to switch to GHC 8.6.5:
$ ghcup install 8.6.5
$ ghcup set 8.6.5
Then, create a blank project with cabal-install:
$ mkdir myproject
$ cd myproject
$ cabal init
Add Spock to the build-depends section of myproject.cabal:
build-depends: base >=4.12 && <4.13
, Spock == 0.13.*
Finally, you can run:
$ cabal build
Which will install Spock and its dependencies before building the project. (Note that you generally don't need to use cabal install to install libraries with cabal-install 3.)
It is presumably possible to make it work with Stack as well, by changing to the lts-14.27 resolver (the latest one that uses GHC 8.6.5), tracking down all dependency versions that need to be overriden (as you had began to do) and manually adding them to the extra-deps of stack.yaml.

Is there a tool for upgrading the dependecies' upper bounds to the latest versions of each dependency?

I'm trying to upgrade the dependencies of the pipes-files package, so that it can be included in the latest stack LTS. The pipes-files package does not contain a stack.yaml file, and the pipes-files.cabal file contains quite some upper and lower bounds on its dependencies, e.g.:
base >=4.7 && <4.10
, transformers >=0.3 && <0.6
, transformers-base >=0.3 && <0.6
-- and quite some more ...
Is there a tool that I can run to get the latest versions of each of these dependencies? The closest thing I could find was packdeps but it will require me to search for the dependencies one by one.
Preliminary notes:
hierarchy, a dependency of pipes-files, has the same issue you are trying to work around -- it is not in Stackage and has version bounds outdated with respect to the latest LTS. That means you'll first have to get it to build successfully, and then add your tweaked version of it to the extra-deps in the stack.yaml of pipes-files.
cabal gen-bounds, which "suggest[s] dependency version bounds that conform to Package Versioning Policy", is, in principle, the right tool for the job. However, getting cabal-install to behave according to the restrictions of a Stack-centric environment is not always straightforward. While this seems enough to run cabal gen-bounds from a bash shell in the absence of a Stack-independent GHC installation...
PATH=$PATH:$(stack path --compiler-bin) cabal gen-bounds
... I couldn't figure out how to get it to follow the version restrictions of the Stack(age) snapshot -- in particular, the --package-db option, which can be helpful with commands such as cabal configure, doesn't seem to be accepted by gen-bounds.
As I don't know how to make cabal gen-bounds and Stack cooperate, I will suggest a somewhat more convoluted method, but one that doesn't require using cabal-install directly. It uses Jenga, a tool that can retrieve the version information left implicit by your choice of Stackage snapshot. Jenga is not on Stackage; to install it with Stack, grab the sources from GitHub (or with stack unpack jenga) and then run stack init --solver followed by stack install.
Remove all version bounds from the hierarchy.cabal file (or whatever the relevant .cabal file is).
stack init --solver, to create a stack.yaml file with any extra-deps that might be necessary. (You can use --resolver to explicitly choose the snapshot to be used.)
stack build, as a sanity check that the package is buildable.
In the generated stack.yaml, check whether the extra-deps field is commented out; if so, uncomment it. This is necessary for step #6 to work.
jenga -i hierarchy.cabal, which will print the exact dependency versions Stack would use to build the package.
Paste the versions Jenga gave you into the build-depends of the .cabal file, adjusting then if desired (at a minimum, you'll probably want to relax the minor version bounds for PVP compliance -- e.g. changing base == 4.9.1.0 to base == 4.9.*).

How do you get Cabal to print all available versions of a package?

How do you get Cabal to print all available versions of a package? Running cabal -v info package-name prints something like this; in case many versions are available:
Versions available: (0.1.5.5), (0.1.5.6), (0.1.6.3), (0.1.6.4), 0.1.6.5,
0.2.4.2, 0.2.5.0, 0.2.6.0, 0.2.7.0 (and 26 others)
An indirect way to accomplish this, e.g. for the text package is
cabal list --simple-output text | awk '$1=="text" { print $2 }'
The post-processing via awk is needed because cabal list currently only supports substring matching, but not exact matching.
I don't know how to get cabal to do it, but the information is at least available. Check the Hackage page for the package; typically this is http://hackage.haskell.org/package/<package-name>. It will include a complete list of available versions right after the package description.

Is there any way to define flags for cabal dependencies?

I recently ran into a Cabal issue that I only managed to solve by manually installing transformers-compat with the -f transformers3 flag in my cabal sandbox before running cabal install for my project.
Is there any way to indicate in my application's .cabal file that I depend on a library so that it is built with the specific build flag?
Newer versions of Cabal let you specify constraints in your cabal.project.local or cabal.project file. For example:
constraints: hmatrix +openblas
Is there any way to indicate in my application's .cabal file that I depend on a library so that it is built with the specific build flag?
No, but in your case this is not actually a problem in the solver and is rather and uninformative error (caused by someone's less than judicious uses of flags).
Looks like it's not possible to specify such a dependency via the build-depends field in your .cabal file. buildDepends is defined as [Dependency], where data Dependency = Dependency PackageName VersionRange. You can use cabal install --constraint="transformers-compat +transformers3", though.
Looking at the transformers-compat.cabal file, I think that the solver should be able to figure out the correct flag assignment if you constrain your dependency on transformers appropriately. E.g. build-depends: transformers >= 0.3 && < 0.4 should force the solver to choose transformers-compat +transformers3. If this doesn't work, it may be a bug in the solver.
I also struggled for a long time to find a solution to this problem. I just found one! You have to modify the global cabal configuration file at ~/.cabal/config. Add a constraints line like this to the initial section of the file:
constraints: hmatrix +openblas
This enables the openblas flag for the hmatrix package. It will be used automatically the next time the package is installed. If there is a way to set such a flag locally for a sandbox, I could not find it.
You cannot do this with Cabal.
One way to do this is to use Stack. Edit your stack.yaml to include
flags:
transformers-compat:
transformers3: true
See also the section on flags.
cabal now supports an elegant way to do this similar to stack, through cabal.project configuration options.
package transformers-compat
flags: +transformers3
will add the flag transformers3 when building the package transformers-compat.
There are a couple of ways to constrain the version for installation.
Add lower and upper bounds to package versions in the cabal file like Mikhail mentioned above, example of such a file here
Additionally, you can override the settings in the .cabal file with the flag cabal install --constraint="bar-2.1"
To remove a specific version of a package:
In a sandbox you can unregister a version with cabal sandbox hc-pkg unregister bar-2.1
Global unregistering can be done with this command outside of sandbox ghc-pkg unregister bar-2.1

Minimal cabal file for use in sandbox

I’m trying to write a project with the Hakyll library. In order to avoid messing up with my system, I’d install it in a cabal sandbox in the same folder where my Hakyll project lives.
Being more or less a beginner, I’m still struggling with getting the pest practices right. A simple approach would be to just do
$ cabal sandbox init
$ cabal install hakyll
$ cabal exec ghc -- --make site.hs
where the last line compiles my Hakyll generator using the libraries in the sandbox. The obvious disadvantage is that this is not reproducible. The main version of Hakyll could have change when I try to run it again from a clean checkout.
Another approach would be to write a proper project.cabal file (For example like this: chromaticleaves.cabal) and then do cabal install or cabal run.
However, I feel that this may be a bit too much information. As I do not intend to publish this project any more than needed, I’m not really convinced I need to put a project name and version number in there. (For example, in a Ruby Gemfile, I would also only specify the libraries and nothing else unless I wanted to publish a gem myself.)
So, eventually I figured that with a file like
$ cat project.cabal
cabal-version: >= 1.2
library
build-depends: base >=4.6
, containers
, process
, hakyll >=4.5
, pandoc
, pandoc-types
I can type
$ cabal sandbox init
$ cabal install --only-dependencies
$ cabal exec ghc -- --make site.hs
and it seems to download all dependencies and is able to compile the file.
Is this a reasonable approach or is the best practice really to give a full specification with name, version and executable sections in the cabal file?
Edit: Apparently, my approach does not let me do cabal repl. So either there exists a completely different way of doing it or it seems I have to go with a fuller specification.
I use your first approach myself for my Hakyll-based webpage. You don't need to create a .cabal file to pin the Hakyll version, you only need to add the following line to cabal.config:
constraints: hakyll == 4.5
I think that cabal repl will work with this approach, but you will need to load site.hs manually (:l site.hs). Or you can use cabal exec ghci -- site.hs.

Resources