How does Stack decide on dependencies? - haskell

I just made a fork to fix a bug in html-conduit, which my templating library depended on. I maintain an app that depends on that templating library.
So, I updated my library's stack.yaml to point to the fork:
extra-deps:
[...]
- git: https://github.com/emhoracek/xml.git
commit: 3e1bd12882d7c452d76e39e1db1b95577f38d4d7
subdirs:
- xml-conduit
- html-conduit
And wrote a test to make sure that updating that dependency fixed the bug. It did! Yay.
Then I updated my app to point to the updated templating library:
packages:
[...]
- location:
git: https://github.com/positiondev/larceny
commit: ba743c58ff4ac2606f67336e5e557deacb416ed8
extra-dep: true
I checked to make sure that this fixed the bug in my app, but it didn't. Until I added my fork of html-conduit to my app's extra-deps, it still had the bug.
What's going on? Why doesn't Stack use the version of html-conduit I specified in my library's stack.yaml when it's deciding what version my app should use?

Any stack command only references a single stack.yaml file - the one that's in the current directory, or maybe some parent directory. Libraries you depend on don't need to have a stack.yaml file, and it's ignored if it exists.
This keeps the version specification simple. There are no rules for handling the case where two stack.yaml files ask for different versions of the same library, because no build ever consults two stack.yaml files.
On the other hand, the .cabal file for each library is consulted, so you will get an error early in the build if some .cabal file requires a library for which the stack.yaml doesn't specify a version, or if the version bounds in a .cabal don't match the specific version in stack.yaml.

Related

Install package that is not on stackage but on hackage

I'm trying to use a library that's on hackage, but not on stackage.
Currently, the code doesn't seem to be hosted on git anywhere (although I could "fork" it).
Are there any better ways than to just download the library locally and tell stack.yaml where to find it?
The library is parse-dimacs by the way.
stack allows you to specify dependencies that are not included in the (Stackage) snapshot as extra-deps in your stack.yaml.
To use parse-dimacs in your project, you'd add this stanza to your stack.yaml:
extra-deps:
- parse-dimacs-1.3

What does 'no specified version' mean in my Cabal build?

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.

How can I use my own build of a package with stack?

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

Create hackage package that can be installed with stack

When running stack sdist in my project directory, the stack.yaml file isn't included in the tarball (this seems to be expected).
Consequently, when I upload the tarball to hackage, then stack install mypackage it complains about missing dependencies (extra-deps) which I specified in the stack.yaml file.
$ stack install pandoc-placetable
Run from outside a project, using implicit global project config
Using resolver: lts-5.17 from implicit global project's config file: ~/.stack/global-project/stack.yaml
While constructing the BuildPlan the following exceptions were encountered:
-- Failure when adding dependencies:
spreadsheet: needed (>=0.1.3 && <0.1.4), not present in build plan (latest applicable is 0.1.3.4)
needed for package: pandoc-placetable-0.4
-- While attempting to add dependency,
Could not find package spreadsheet in known packages
Recommended action: try adding the following to your extra-deps in /Users/maurobieg/.stack/global-project/stack.yaml
- spreadsheet-0.1.3.4
Or what's the recommended way to make a hackage package stack-installable if it has further hackage dependencies?
Update: I just added extra-source-files: stack.yaml to the cabal file and the stack.yaml is indeed included in the tarbal of the newly published version. Nevertheless, stack install pandoc-placetable-0.4.1 still comes up with the same error.
I could also just tell people who don't want to install cabal-install on their system to clone from GitHub, then build with stack. Is that the recommended approach for tiny packages? Or should I ask them to include the dependency of pandoc-placetable (i.e. spreadsheet) in their global stack.yaml? Smells like polluting a global file...
As mentioned by #mgsloan in the comments above: There's an open stack issue about using stack.yaml from hackage package.
I guess until it's fixed I'll just tell people to clone from GitHub (or as mentioned by #MichaelSnoyman to stack unpack) and then cd into the newly created directory and stack install there.

How to get stack to save dependencies?

I'm using the stack install command to save dependencies for a new project. How do I get it to save those dependencies into stack.yaml? Unless I'm missing something, I can't see where stack is recording the project dependencies and I can't seem to find anything in a docs about this.
You still keep your dependencies in a .cabal file. From the Stack FAQ:
A .cabal file is provided for each package, and defines all package-level metadata just like it does in the cabal-install world: modules, executables, test suites, etc. No change at all on this front.
A stack.yaml file references 1 or more packages, and provides information on where dependencies come from.
If you need additional versions of dependencies than the LTS Haskell snapshot you're using, you'll add them to the extra-deps portion of the stack.yaml file.

Resources