How to get Stack to rewrite my Setup.hs file, after changing to Custom build type? - haskell

My project has local external dependencies.
So, I've changed the build-type field, in my *.cabal file, to "Custom" and added these sections to my stack.yaml file:
- location: ../loc_deps
subdirs:
- loc_dep1
- loc_dep2
extra-dep: true
explicit-setup-deps:
"*": true # change the default
But, I can't figure out how to get Stack to rewrite my Setup.hs file, to track these local external dependencies.
In response to the first comment, below:
Is this a sufficient Setup.hs for a Custom build-type?:
import Distribution.Simple
main = defaultMain
I'm expecting that if I touch ../loc_deps/loc_dep1/NeededModule.hs and then run a "stack build", I'll see NeededModule.hs get recompiled, but I'm not seeing that.
In response to #mgsloan (first comment below):
Wrt/ this:
Dependencies do not go in your custom Setup.hs
So, then, is this verbiage, taken from the stack.yaml fields descriptions page, out of date?:
Decide whether a custom Setup.hs script should be run with an explicit
list of dependencies, based on the dependencies of the package itself.
It associates the name of a local package with a boolean. When it's
true, the Setup.hs script is built with an explicit list of packages.

Related

How to set up conditional dependency for Stack project?

I'm trying to enable my Stack-based Haskell project to apply a certain GHC plugin when the user requires it.
I have successfully added the -fplugin flags through the ghc-options. As far as I know I have to add the plugin package as a dependency in my package.yaml file. However I would like to configure the project so that the extra dependency is only added if the user requires it (with a flag set, environment variable or some other means).
I have tried to use the when keyword in the package.yaml to conditionally enable the dependency:
when:
- condition: flag(useplugin)
then:
dependencies: [ myplugin ]
else:
dependencies: []
However this results in an error coming from cabal:
- 0:0: These flags are used without having been defined: myplugin
I couldn't find the option for package.yaml which would generate the flag definition (like described here) in the generated cabal file.

Using a package that's not on Hackage

I am trying to use EuterpeaLite (https://github.com/Euterpea/EuterpeaLite), but it is not on Hackage.
I imported it like such import EuterpeaLite as EL and I added it to my cabal file like this:
build-depends:
base >=4.7 && <5
, postgresql-simple
, EuterpeaLite
But when I run stack build or stack ghci, I get this error:
Error: While constructing the build plan, the following exceptions were encountered:
In the dependencies for engine-0.1.0.0:
EuterpeaLite needed, but the stack configuration has no specified version (no package with that name found, perhaps there
is a typo in a package's build-depends or an omission from the stack.yaml packages list?)
needed since engine is a build target.
Some different approaches to resolving this:
Plan construction failed.
Is there a special process for non-Hackage packages?
I used the following procedure.
Create a new stack project stack new myproject --resolver=14.27. I needed to specify an older resolver, since EuterpeaLite wouldn't build with lts-15.3
In the myproject directory, add the following lines to stack.yaml:
extra-deps:
- git: https://github.com/Euterpea/EuterpeaLite.git
commit: 5fe2d129bd3087dd78c0feaf4d35fc03ffd36215
Also in the myproject directory, I added the following dependency to package.yaml:
dependencies:
- base >= 4.7 && < 5
- EuterpeaLite # <- added this line
Ran stack build in the myproject directory.
As you noted, instead of using package.yaml, you could change your .cabal file.

Stack won't resolve a 'hidden' dependency

I am working on my first major Haskell application, and want to add mockery to create disposable test WAI threads. Importing mockery and running stack test resulted in the compiler error:
Failed to load interface for ‘Test.Mockery.Directory’
It is a member of the hidden package ‘mockery-0.3.5’.
Perhaps you need to add ‘mockery’ to the build-depends in your .cabal file.
Use -v to see a list of the files searched for.
So, I added mockery to my cabal file under test dependencies. However, when I run stack build or stack test mockery is automatically removed from the cabal file.
I have also tried listing mockery-0.3.5 under extra-deps in the stack.yaml file. This unsurprisingly didn't work, since mockery is part of my lts, and extra deps is for packages outside of lts.
How can I get stack to recognize that mockery should be included as a dependency to to project?
Here is my stack.yaml:
flags: {}
ghc-options:
! '*': -Wall
packages:
- .
extra-deps: [
]
resolver: lts-9.5
I'm using stack version 1.5.1
I imagine this is a stupid build issue and look forward to confronting my obvious oversight.
In stack.yaml you declare the Stackage LTS version, a curated list of hackage dependencies that you want to depend on. You can also depend on local packages and packages in git that are not in Hackage. You may also change the versions of the packages in LTS as long as they respect the constraints of the other dependencies.
package.yaml is the build file. Any packages you want to import directly in your Haskell code must be declared in here as dependencies, even if they are explicitly declared in the stack.yaml.
Finally, when you see It is a member of the hidden package, that means that one of your dependencies is using that package, but it is not declared as a dependency in your build file.

What is the preferred way to write quick Haskell test programs that depend on Stack libraries in local directories?

I have a Haskell library that I am developing using Stack. As I am developing the library, I like to write small test/experimentation programs that use the library. I keep a collection of these test programs for myself in a directory locally. These test modules are very quick and informal, and not appropriate to include as unit tests in the committed library code. Typically, most of them aren't even maintained and won't compile against the latest version of the library, but I keep them around in case I want to update them later. When I'm working on a test program, I want it to build against my working copy of the library, with any changes that I've made to the library locally.
How should I set up my Stack build environment for this situation? Here are some options I've tried, and the problems with each options.
Two Cabal packages, one Stack configuration. The stack.yaml file lists both packages and defines the build environment for both at once.
Problem: The stack.yaml file needs to be included as part of the committed library source code, so that other developers can build the library from source reproducibly. I don't want the public stack.yaml file for my library to include build information for my local test projects.
Problem: As far as I know, to make this work I need to have a .cabal file that lists all the executables and modules for my test programs. This is annoying to update whenever I want to throw together a quick experimental script, and will fail to build any of the test programs if I have even a single module that doesn't compile. I can't have a .cabal file with no sections, because Cabal gives "No executables, libraries,tests, or benchmarks found. Nothing to do.", and because this offers nowhere to list build-depends.
Create a Cabal sandbox for the test programs. Use cabal sandbox add-source to add the local library as a package. See also this answer.
Problem: Using Cabal sandboxes instead of Stack reintroduces a lot of the dependency problems that Stack is supposed to fix, such as using the system-global GHC instead of the GHC defined by the resolver.
Have a separate stack.yaml for the test programs. Add the library under packages as location: 'C:\Path\To\Local\Library' and set extra-dep: true for that dependency. (See here for more info on this feature.) Don't put any other Cabal packages under packages in the stack.yaml for the test programs. Use stack runghc to invoke test programs within the scope of their stack.yaml.
Problem: I just can't get this one to work. Running stack build inside the test program directory gives "Error parsing targets: The project contains no local packages (packages not marked with 'extra-dep')". Running stack runghc acts as if no dependencies are present at all. I don't want to add a Cabal package for the test programs because this has the same problem as option 1 with needing to construct an explicit .cabal file describing the modules to build.
Problem: Stack build configuration info that I want to be identical between the library and the test programs has to be copied manually. For example, if I change the resolver in my library's stack.yaml, I also need to change it in the stack.yaml for my test programs separately.
Have a directory inside my working copy of the library that contains all of my test programs. Use stack runghc to invoke test programs in the context of the library.
Problem: I'd like the directory with my test programs to be outside of the directory containing my library source code and build configuration, so that I don't have to tell the version control for my library to ignore my test code, and can have my own local version control just for the test programs.
Problem: Only works with a single local library dependency. If my test programs need to depend on local working copies of two different libraries with their own stack.yaml files, I'm out of luck.
Add a symbolic link inside my working copy of the library to a separate directory that contains all of my test programs. Navigate through the symlink and use stack runghc to invoke test programs in the context of the library.
Problem: Super awkward to use, especially since I'm on Windows and Windows has terrible symlink support.
Problem: Still need to tell my version control system to ignore the symlink.
Problem: Still only works with a single library dependency.
If only one local library is involved, I use option 4. You can put your tests outside the directory of your library, and either invoke stack from the directory of your library, or using --stack-yaml path/to/library/stack.yaml.
Otherwise, I use option 3, creating a separate stack project without setting extra-dep.
...
packages:
- 'path/to/package1'
- 'path/to/package2'
...
I can't think of a good workaround for the issue of configuration duplication. There would otherwise be conflicts if multiple packages specified different resolvers/package versions.
Edit: Actually a stub library works better, so edited to add.
I think the way to get #3 to work is -- under your scratch program directory -- (1) add . under packages in stack.yaml alongside the location/extra-dep: true package:
packages:
- '.'
- location: ../mylib
extra-dep: true
(2) create an executable clause in scratch.cabal that points to a stub main program (i.e., a "Hello World" program that compiles but need not do anything) which depends on your library:
executable main
hs-source-dirs: src
main-is: Stub.hs
build-depends: base
, mylib
default-language: Haskell2010
or a library clause with no exposed modules, again that depends on your mylib library:
library
hs-source-dirs: src
build-depends: base >= 4.7 && < 5
, mylib
default-language: Haskell2010
and (3) run stack build in the scratch directory. This should build and register mylib, and now stack runghc Prog1.hs should work fine for running programs that depend on mylib modules.
If you use the executable approach, the stub program is compiled as a side effect but otherwise ignored. If you use the library approach, it looks like the stub library isn't even built; and you then have the option of actually building a scratch library by adding some exposed modules of shared code for your test programs to use, if it's convenient, so the stub library might be best.
None of this solves the problem of keeping stack.yaml info like the resolver version in sync, but it seems to address all the problems you list in 1, 2, 4, and 5. In particular, it should work fine for test programs that depend on multiple local libraries you're developing.

Despite stack solver, Could not find module `Test.Hspec'

This is my stack.yaml file declaring hspec as a extra dependency:
# Specifies the GHC version and set of packages available (e.g., lts-3.5, nightly-2015-09-21, ghc-7.10.2)
resolver: lts-3.8
# Local packages, usually specified by relative directory name
packages:
- '.'
# Packages to be pulled from upstream that are not in the resolver (e.g., acme-missiles-0.3)
extra-deps:
- hspec-2.2.0
when I run stack solver it says there is no change to be done:
root#5d7daa2aec0a:/src/test_stack/a-test/src# stack solver
This command is not guaranteed to give you a perfect build plan
It's possible that even with the changes generated below, you will still need to do some manual tweaking
Asking cabal to calculate a build plan, please wait
No needed changes found
To automatically modify your stack.yaml file, rerun with '--modify-stack-yaml'
this is my source file (only to check that I could use Hspec with stack):
module Main where
import Test.Hspec
main :: IO ()
main = do
putStrLn "hello world"
and when I run stack build I get:
2015-10-05 22:24:08.450413: [warn] Could not find module `Test.Hspec' #(stack_Bp003b8iWaELtdr693pSPs:Stack.Build.Execute src/Stack/Build/Execute.hs:1241:35)
I thought stack solver was ensuring that extra dependencies are ok.
What I am doing wrong ?
It's the first time I use stack.
While stack replaces cabal-install, the command line tool for building and installing packages, it still uses the Cabal packaging infrastructure. In particular, that means projects built with stack are still Cabal-compatible packages with .cabal files, and all of their dependencies should be listed in the build-depends section of the .cabal file with appropriate version ranges. That holds even if the dependency is also specified in the stack.yaml file extra-deps field, as that field serves a different purpose (namely, giving stack an exact version to use when building the package).

Resources