The recent Travis CI build of the development version of my Haskell package reports the error
MissingH must match >=1.3.0.1, but the stack configuration has no specified version (latest matching version is 1.4.0.1)
when building for GHC 8.6.1, even though I have
MissingH >=1.3.0.1
in my build-depends.
I don't understand this error: it seems contradictory. I have no upper limit on MissingH, so why is it erroring and not using the latest?
You need to add MissingH to stack.yaml.
extra-deps:
- 'MissingH-1.4.0.1'
Your package's *.cabal file says what versions of dependencies are compatible with your package. It is a loose specification, not all combinations may actually work (because they may have conflicting bounds on transitive dependencies, or there is some unforeseen breakage with a particular version you haven't tested with).
In contrast, stack.yaml describes a particular snapshot of packages, pinned to specific versions. This precisely says "my package is known to work with those versions". Of course, it is tedious to maintain the version of every dependency, and for that the Stackage team maintains a "resolver", a curated set of package versions known to work together, that you can use to specify the version of many packages at once, by setting the resolver: field of stack.yaml appropriately. A resolver only lists a subset of packages on Hackage, so when one of your dependencies is not in there, you need to add it to your stack.yaml as an extra-dep.
Update: following the discussion, some more details about configuring travis are necessary.
First, my current preferred solution for CI of Haskell projects is to not bother with stack and use instead https://github.com/haskell-CI/haskell-ci which generates a travis script using cabal-install.
Now for a less radical solution.
Currently the travis script is only varying the --resolver option, but as far as I can tell there is no command line option to add an extra-dep. It seems stack.yaml files are the only way for that. Furthermore, we only want to specify MissingH as an extra-dep for the latest nightlies, because LTS'es already include it.
Thus I suggest the following:
Create a separate stack.yaml for the nightly resolver only, call it something else since you already have one, for example stack-nightly.yaml
packages:
- .
extra-deps:
- 'MissingH-1.4.0.1'
Set an environment variable to point to stack-nightly.yaml when the resolver is a nightly, maybe:
env:
...
- $RESOLVER=nightly STACK_YAML=stack-nightly.yaml
# Not sure of the syntax.
Otherwise you can use the --stack-yaml command line option.
Related
Say I want to tinker with a few hackage packages that depend on each other and run
stack unpack foo-1.2.0
and
stack unpack bar-1.0.0
where bar depends on foo.
Now, to build my modified bar with my modified foo, I specify in my bar.cabal:
build-depends:
foo == 1.2.0
and add to my bar's stack.yaml:
packages:
- .
- rel/path/to/foo-1.2.0/
This works, and builds fine but it seems that if a dependency of bar, say some-package, itself depends on foo it will default to the hackage version rather than compile with my modified version despite my modified version meeting the version constraints. Is there a way to force other dependencies further up the chain to use my local version of the package during the build process? I appreciate this is a very unusual use case.
Weirdly I'm able to build fine but trying to load into stack ghci fails with:
Couldn't match type `foo-1.2.0:Some.Type.InFoo.aDataType`
with `aDataType`
NB: `aDataType` is defined at
`full/path/to/foo-1.2.0/Some/Type/InFoo.hs:(23,1)-(28-60)`
`foo-1.2.0:Some.Type.InFoo.aDataType`
is defined in `Some.Type.InFoo`
in package `foo-1.2.0`
Expected type: `aDataType`
Actual type: `foo-1.2.0:Some.Type.InFoo.aDataType`
According to the Cabal User Guide, when developing a project with several local packages:
Local packages, as well as the external packages [...] which depend
on them, are built inplace, meaning that they are always built
specifically for the project and are not installed globally.
So it seems that even external packages (that is, packages from Hackage or another package repository) will use the local packages, at the cost of needing to be rebuilt for the current project.
Is it possible to install package from sources with something similar to stack build package-name? (latter works with packages on Stackage, but not with custom ones)
Um, stack build (within the source directory)?
Stack doesn't really have a notion of installing libraries though, it only installs executables. To “install” locally-sourced packages, you need to specify what for you want them installed: add them as dependencies to another project, via a location: field in the packages: field in that project's stack.yaml file.
That's arguably sensible since, one might say, there's nothing you can do with an installed library except invoking it in another Haskell project (or in a REPL, which you can get with stack ghci). I personally don't hold with that though, I like actually being able to say install that library now. Which is one of the reasons I have always stuck to good old cabal-install rather than Stack. With that, you can just
cabal install
from within the source directory.
Cabal-install has often been criticised: its local installs can easily get out of sync and then you have weird dependency conflicts and need to rebuild lots of stuff. I never found this that much of a problem, and anyway this has been adressed in recent Cabal through Nix-style builds, which never produce conflicts.
user$: stack install dictionaries
Error: While constructing the build plan, the following exceptions were encountered:
In the dependencies for dictionaries-0.1.0.0:
binary-0.8.3.0 must match >=0.7.5 && <0.8 (latest applicable is 0.7.6.1)
time-1.6.0.1 must match >=1.5.0 && <1.6 (latest applicable is 1.5.0.1)
With the above command, I want to install the dictionaries package globally.
What are my options here?
I plan to stack unpack dictionaries, and then modify the versions.
But then how to install the modified 'local' package globally?
What's the best practices here?
Thanks
Easiest one: Add allow-newer: true to stack.yaml
It would to be the solution in this case. It solves the upper version limitation problem like yours. But of course there is possibility of build failure.
Maybe possible one: Change resolver to latest nightly
That failure occurs sometimes on nightly snapshot. And usually repaired soon by library update and new nightly snapshot. If you are using old snapshot, change it to latest. Or waiting may be one of solution.
Most general one: Make dependency to modified local package
You can do it by adding the package path to stack.yaml packages:. Then stack will use it instead of snapshot one.
The way you want is probably not a good idea. Even if that's possible, how are you going to handle with the many version of snapshot case? Local dependencies should be specified to each package.
With the above command, I want to install the dictionaries package globally.
(Preliminary note: by "globally", I will assume you mean globally for your user, as opposed to a system-wide installation.)
dictionaries is not in any Stackage snapshot. As far as I'm aware of, that means you cannot install it globally, as for libraries that is only an option if the package is in a snapshot. Cf. Stack issue #2656 -- while the planned feature described there sounds like what you are trying to do, there is a caveat:
Should also warn when it isn't used with --copy-bins, and if there are targets that don't have executables, as these both indicate a misunderstanding about how it works.
That being so, my suggestion is to install the package per-project, using the packages field with an extra-dep key -- that is, the "most general" solution in jeiea's answer.
The bigger picture is that I'm trying to use the sdl2 package from Stackage (lts 8.1). Though, I'm having a bit of an issue; The package is missing a compiler flag, as detailed in this issue on GitHub. As such, it doesn't build properly.
However, if I clone the repository, I can add the missing compiler flag to the .cabal file and build it myself, which solves the issue. I now have a working build of the package.
So my question is: How can I, in a separate project, use my own working build of the sdl2 package, instead of the one from Stackage?
There are a few ways of doing that with Stack. The one I like the most, and which sounds like a good fit for your scenario, is uploading the repository with your fork to GitHub (or wherever else you find appropriate) and then adding a reference to the online repository as an extra-dep to the packages section of stack.yaml. For the sake of illustration, here is the packages section for a project of mine in which I had to do that:
packages:
- '.'
- location:
git: https://github.com/duplode/threepenny-gui
commit: 7e4e3a41cbb5e55312d4375612790d633ccf1e7a
extra-dep: true
I'm attempting to start a new project using the Snap web framework. I used snap init to get my basic skeleton working. I also put http://www.stackage.org/lts/cabal.config next to my .cabal file. I didn't uncomment the line to use Stackage exclusively. So I tried to build and it failed and couldn't find the version of lens required by my .cabal file. The cabal.config file from Stackage specifies a version of lens that is not the same as the one in my .cabal file. So I deleted every constraint from my package list and did the usual cabal install --only-dep -j8 --enable-test and it worked!
However, I have always been told that package versions should be constrained. So when working with Stackage is it okay to leave package versions unconstrained? Should I downgrade my packages to the ones available in Stackage instead?
As far as I understand a cabal.config file specifies a set of dependencies with the specific versions that satisfy dependencies, so how does Stackage work? Is it just a subset of packages from Hackage that are proven to be compatible? Do they host their own packages or rely on Hackage for downloads?
Thanks in advance :)
Both options are available. The default option is what you did, and still goes to hackage to get the packages. You just added a filter to your cabal that prevents you from using any version of a package included in Stackage that was not tested to work together with all of the other packages.
The other option is to simply point your cabal repo to a Stackage url, and then you will download packages directly from the Stackage server. That server will only serve packages that are known to work together, so there is no need for additional constraints in your cabal file. I actually prefer this way of working.
In both cases, if you have additional constraints in your cabal file that are incompatible with the Stackage restrictions, your build will fail. If you use the first option, you will get dependency conflicts. When using the second option, the Stackage server will simply report that it does not have that specific package/version.