I have a Haskell stack project whose cabal file is divided as follows:
library
exposed-modules:
Godot.Api
Godot.Api.Auto
-- ...
library generate
exposed-modules:
Generate
Spec
Types
Types.Internal
-- ...
When I run stack build it seems to only build the first library, but what I want stack to do is build just library generate. How do I do this? The following doesn't seem to work:
stack build project-name:library:generate # doesn't seem to work
stack build project-name:lib:generate # doesn't seem to work
Unfortunately, you can't write multiple librarys in one cabal file.
So you have to make one cabal file per library (usually make one directory per one cabal file).
Then, list them up in the stack.yaml:
packages:
- your-main-library
- generate
Then, run stack <the-library-to-build> to build a specific library:
stack build generate
FYI. Here's a project which contains several libraries: https://github.com/iij-ii/direct-hs
Related
|-aseCswk2
|-app
|-Main.hs
|-src
|-Libs.hs
|-test
|-Spec.hs
|-aseCswk2.cabal
|-Setup.hs
|-package.yaml
...
So i have a Haskell project that uses a Stack build system and is laid out as the example above. If i use $ stack test then my functions in my Libs.hs file are tested with the cases in my Spec.hs file. If i use $ stack build then my file builds successfully and i can use the functions inside $ stack ghci.
However, i want to create an executable of the my Main.hs file but don't know how this is possible. I have tried compiling it using $ ghc Main.hs inside the app directory but get an error saying 'Failed to load interface for Lib' even though i have included it as an import. I have also tried $stack build aseCswk2:exe:aseCswk2-exe but no .o files are created to run.
Haskell-stack builds the executable in the hidden .stack-work directory. You can find out where the binaries are located that stack uses with:
$ stack path --local-install-root
/haskell/app/.stack-work/install/x86_64-linux/3fa5b3c3fbcd473981eef72c68d572129654cbb7c23af146b50d90e29c41b62f/8.6.5
In this directory, there is, if you build the application, a bin/ directory where the binary is located that has been built.
You can also run the application with:
$ stack run
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.
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).
I created a new project using the stack new Proj-Name simple command, and in a file I created within the /src directory imported a module outside of GHC's base library, import System.Process. Running stack build was successful, and the file worked as I expected it to. However, when I ran stack ghci within the same directory it did not have System.Process listed as an importable module.
How do I make it so that all my imported modules are importable within stack ghci?
While the information in Nicholas MontaƱo's answer is correct, I believe it doesn't reach the root of the issue. The likely cause of the problem is that the newly created source file wasn't declared in the cabal file, leading stack to ignore it. Every source file in a project must be declared in a section of the cabal file, be it exposed-modules (for parts of libraries which you want to expose to the users of your code) or other-modules (for internal modules which you do not want to expose).
When you run stack new ..., even with the simple template, you'll notice that several files are created which allow for stack to work. One of these is a Proj_Name.cabal file, and if you open it, you'll notice that under the executable Proj_Name section of the file there's a main-is: Main.hs line.
The default main-is file will be Main.hs, but it may be anything. Your imports should go within whatever file you want to act as your main file. So in this case, you can simply put whatever the name of that file you created (which has the System.Process import) in place of Main.hs in that line.
Following this, run stack build, add whatever dependencies it tells you to under the build-depends: base >= 4.7 && < 5 line in Proj_Name.cabal, which in this case will look like:
build-depends: base >= 4.7 && < 5
, process
run stack build again (if there are any further issues you might want to consult the stack guide, and now stack ghci should have all the modules that you imported in that file available to it.
I want to use reactive-banana in my new Haskell project. I never used cabal-install or stack before. I created a directory and initialized project files in it using stack new. I see now 2 files in the directory: new-template.cabal and stack.yaml.
How do I set dependencies and make sure they are downloaded and compiled?
At first I tried to add - reactive-banana-0.8.0.2 in stack.yaml under extra-deps:, but both stack build and stack solver didn't download it. Then I augmented a part called library in new-template.cabal to this:
library
hs-source-dirs: src
exposed-modules: Lib
build-depends: base >= 4.7 && < 5
, reactive-banana >= 0.8
default-language: Haskell2010
Every time I tried to run stack build, it crashed with an error and suggestion to add some package to stack.yaml under extra-deps:, and this happened three times until finally all packages installed, and I could import them in stack ghci REPL.
So my question is, what is the idiomatic way to use stack? Which of these 2 files should I use to specify dependencies and other project metadata? What is the sample workflow of an average Haskell developer with stack?
When using stack I generally don't put any versions bounds in my .cabal file. I let the resolver and extra-deps setting in the stack.yaml file determine which versions of packages to select.
Here is a stack.yaml file which brings in reactive-banana-0.8.1.2:
flags: {}
packages:
- '.'
extra-deps:
- reactive-banana-0.8.1.2
- psqueues-0.2.0.2
resolver: lts-2.17
In my .cabal file I just have:
build-depends: base >= 4.7 && < 5, reactive-banana
The reactive-banana version is pinned by the stack.yaml file.
If you want to use GHC 7.10 change the resolver to something like nightly-2015-06-17.
I determine the extra-deps iteratively, by just running stack build and adding whatever dependencies are missing to the stack.yaml file until all dependencies are satisfied.
You will only need to do this with packages which are not in Stackage - like reactive-banana. A great many of commonly used packages are in Stackage and their versions will be determined by the resolver setting.
In the default configuration, stack works with two package databases: a centralised per-user one and a project-specific one. The centralised database only pulls packages from Stackage, a subset of Hackage with known-to-be-compatible packages, while you can put whatever you want on the project-specific database. All packages you use must be in the cabal file, but those not on Stackage (that is, the ones that will go to the project-specific database) must also be listed in the extra-deps section of stack.yaml. reactive-banana is not on Stackage, so you need to add it to stack.yaml, like this:
# etc.
extra-deps:
- reactive-banana-0.8.1.2
# etc.
stack solver can fill in the extra dependencies in stack.yaml for you.