How does one have multiple libraries using hpack? - haskell

I'd like to organize my project into different libraries, since eventually I may be splitting some out to external repositories.
In a .cabal file I can have multiple libraries (one unnamed, and multiple named, I believe):
library
import: servant-deps
exposed-modules:
App
other-modules:
Paths_cow_streamer
hs-source-dirs:
src
build-depends:
servant-server >= 0.15
library sxapi
import: servant-deps
exposed-modules:
SxClient
other-modules:
Paths_cow_streamer
hs-source-dirs:
sxapi
build-depends:
http-client
Initially I tried like this in my hpack package.yaml:
library:
bar:
source-dirs:
- src
dependencies:
- servant-server >= 0.14
- wai
- warp
foo:
source-dirs:
- sxapi
dependencies:
- servant-server >= 0.14
- wai
- warp
But in this case, none of the entries seemed to be interpreted correctly, since e.g. source-dirs weren't present in the generated cabal file.
I also tried this, but unsurprisingly, one of the library definitions was overwritten:
library:
source-dirs:
- src
dependencies:
- servant-server >= 0.14
- wai
- warp
library:
source-dirs:
- sxapi
dependencies:
- servant-server >= 0.14
- wai
- warp

As per the documentation of hpack (https://github.com/sol/hpack#top-level-fields) you use the internal-libraries header for your internal (named) libraries.

Related

Re-use tests between packages in Stack

I'm curious if it's possible to expose test folder of one package, so another package in multi-package Stack setup could re-use test functions & instances:
second-package-test -> dependsOn -> first-package-test
The first package has the following lines in package.yaml:
tests:
first-package-test:
main: Spec.hs
source-dirs: test
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- first-package
- hspec
- QuickCheck
- quickcheck-instances
- quickcheck-classes
And the second package that should rely on the first one has the following setup:
stack.yaml contains:
extra-deps:
- ../first-package <-- it seems that it imports only library, not the tests
package.yaml contains:
tests:
second-package-test:
main: Spec.hs
source-dirs: test
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- second-package
- hspec
- QuickCheck
- quickcheck-instances
- quickcheck-classes
The root aggregation of them looks simple. stack.yaml:
packages:
- first-package
- second-package
I think, in theory, it's possible to create a third package with tests only that are exposed as a library, but wonder if there is a bit more elegant way to achieve the same thing.

Haskell cabal confused about file and module name

In my haskell project, I have the following directory structure (some entries are missing but not relevant to this problem)
- quanthas
- quanthas.cabal
- src/
- QuantHas/
- Settings.hs
My Settings.hs file contains this module header
module QuantHas.Settings(module QuantHas.Settings) where
My cabal file looks like this
Name: QuantHas
Version: 0.0
Description:
QuantHas project is an attempt to port QuantLib to Haskell keeping the functional flavor of Haskell.
License: BSD3
License-file: LICENSE
Build-Type: Simple
Cabal-Version: >=1.10
Library
Build-Depends: base >= 3 && < 5, array >= 0.2
Exposed-modules: QuantHas.Time.Frequency
QuantHas.Time.TimeUnit
QuantHas.Time.Period
QuantHas.Time.Date
QuantHas.Time.DayCounter
QuantHas.Time.BusinessDayConvention
QuantHas.Time.Calendar
QuantHas.Time.Calendars.UnitedKingdom
QuantHas.Time.Schedule
QuantHas.Settings
QuantHas.Require
default-language: Haskell2010
hs-source-dirs: src
-- ghc-options: -Wall
test-suite QuantHas-tests
type: exitcode-stdio-1.0
hs-source-dirs: testsuite
main-is: Tests.hs
default-language: Haskell2010
When I execute
cabal install --enable-tests
I get this message
src/Quanthas/Settings.hs:17:8: error:
File name does not match module name:
Saw: ‘QuantHas.Settings’
Expected: ‘Quanthas.Settings’
This seems wrong. However, what if we do what cabal expects. So the Settings.hs module header now is
module Quanthas.Settings(module Quanthas.Settings) where
Cabal now says
src/QuantHas/Settings.hs:17:8: error:
File name does not match module name:
Saw: ‘Quanthas.Settings’
Expected: ‘QuantHas.Settings’
And it's at this ppint that I give up and turn to SO. Can anyone help me understand what is going on?
Versions info:
Platform: Macbook Pro running MacOS 10.12.3
Haskell: 8.0.1
Cabal: 1.24.0.0
Thanks!
The issue is that there is a typo in one of the import statements in a different module. Since you're on a case-insensitive filesystem (OS X), GHC is able to find the module contents, but upon checking the module header finds it mismatches with the import statement and errors out.

Shared cabal "build-depends" (Haskell) [duplicate]

Here's a .cabal file:
Name: myprogram
Version: 0.1
-- blah blah blah
Cabal-version: >=1.9.2
Executable myprogram
HS-source-dirs: src
Main-is: Main.hs
Build-depends: attoparsec == 0.10.*,
base == 4.3.*,
-- long long list of packages
Test-Suite test
HS-source-dirs: test, src
Type: exitcode-stdio-1.0
Main-is: Main.hs
Build-depends: attoparsec == 0.10.*,
base == 4.3.*,
-- long long list of packages
QuickCheck == 2.4.*
Is there any way I can replace the long list of build-depends packages for the test suite with "same as for the executable, plus QuickCheck"?
Edit: version information.
cabal-dev 0.9
cabal-install 0.10.2
Cabal library 1.10.2.0
GHC 7.0.4
Haskell Platform 2011.4.0.0
NOTE: superseded by phadej's answer suggesting common stanzas.
Is there any way I can replace the long list of build-depends packages for the test suite with "same as for the executable, plus QuickCheck"?
Not that I know of. However, there is a way to only mention the list of build-depends packages once, by structuring your project into three targets:
a library that contains all your code, and needs the long build-depends list.
an executable that consists of only one file, and depends on base and the library from above.
a test-suite that depends on the library from above, and the testing packages you are using.
Maybe this approach is what indygemma's answer proposes, but the Cabal file proposed there will not quite achieve it, as Norman Ramsey points out in a comment. Here's the main points of what you need in a Cabal file. For a full example that works for me, you can look at this Cabal file.
name: my-program
version: ...
library
hs-source-dirs: src-lib
build-depends: base, containers, ...
exposed-modules: My.Program.Main, ...
executable my-program
hs-source-dirs: src-exec
main-is: my-program.hs
Build-depends: base, my-program
test-suite tests
type: exitcode-stdio-1.0
hs-source-dirs: src-test
main-is: tests.hs
other-modules: ...
build-depends: base, my-program, test-framework, ...
Important points:
There are three separate source directories for the three targets. This is necessary to stop GHC from recompiling library files when building the other targets.
All of the application code is in the library. The executable is just a wrapper, like this:
import My.Program.Main (realMain)
main = realMain
The library exposes all modules that are necessary for testing.
The last point highlights the drawback of this approach: You end up having to expose internal modules. The main benefit of this approach is that you have less duplication in the Cabal file, and maybe more importantly, less duplication in the build process: The library code will be built only once, and then linked into both the executable and the test-suite.
Since version 2.2 Cabal supports common stanzas, to dedup build info fields:
https://cabal.readthedocs.io/en/latest/developing-packages.html#common-stanzas
cabal-version: 2.2
name: myprogram
version: 0.1
-- blah blah blah
common deps
build-depends: base ^>= 4.11,
-- long long list of packages
ghc-options: -Wall
library
import: deps
exposed-modules: Foo
test-suite tests
import: deps
type: exitcode-stdio-1.0
main-is: Tests.hs
build-depends: foo
You could also consider using hpack instead of writing the .cabal file by hand:
In hpack's package.yaml format, you can specify a common dependencies field whose entries are added to every components' build-depends field when generating the .cabal file.
For example, see hpack's own package.yaml and the generated hpack.cabal.
To start using hpack with an existing package, you can use hpack-convert which will generate the package.yaml from an existing .cabal file.
To create a new package that uses hpack, you can use stack's simple-hpack template like so: stack new mypkg simple-hpack.
If you use stack for development, you don't have to call hpack manually to regenerate the .cabal file from an updated package.yaml – stack will do that automatically.
No easy way:
you can use m4 and specify your dependencies once, but then you will need to reprocess your Cabal file through m4 whenever you change it.
you can move the code you are testing out to a library, and then specify the library in your Build-depends for the test. That requires you to install a library even just to run the test.
You can just not put the test in the cabal file at all. Build it with ghc --make, which will pull in dependencies. But then you lose cabal integration.
There is an optional library section for .cabal files, which solves your problem.
name: myprogram
version: 0.1
-- blah blah blah
cabal-version: >=1.9.2
library
build-depends: attoparsec == 0.10.*
, base == 4.3.*
-- long long list of packages
executable myprogram
hs-source-dirs: src
main-is: Main.hs
test-suite test
hs-source-dirs: test, src
type: exitcode-stdio-1.0
main-is: Main.hs
build-depends: QuickCheck == 2.4.*

Variable in Cabal (Haskell)

I am trying to write a package in Haskell. This package contains a library and an executable. I am specifying this in the Cabal file. There are three basic components of the library:
1) There are the exposed modules of the library
2) There are internal build-dependencies that should not be exported as part of the library
3) There are external build-dependencies.
There is a bit of overlap in the Cabal file. For the library I write:
exposed-modules: The List of Exposed Modules
other-modules: The List of other modules
build-depends: The List of build dependencies
Then for the executable
other-modules: The list of exposed modules and other modules are needed in the executable
build-depends: The list of build dependencies
What would be nice is if Cabal lets me have a variable.
V1 = List exposed modules
V2 = List other modules
V3 = List build dependencies
Then in the executable, for example, I could do
other-modules: V1,V2
build-depends: V3
Alternatively, I would take a recommendation for a better way to use the Cabal system!
No, this is not possible yet. I think we have a feature request for something like this on the issue tracker somewhere. Note, however, that your executable can depend on the library defined in the same .cabal file, so you don't have to share exposed-modules and other-modules:
Name: some-package
Version: 0.1
[...]
Library
build-depends: some-dependency >= 1.0, ...
exposed-modules: A, B, C
other-modules: C, D, E
[...]
Executable some-exe
main-is: SomeExe.hs
build-depends: some-package == 0.1
For a real-world example, see here.

How to avoid recompiling in this cabal file?

I've been working on this Haskell project, and I have a cabal file for it. Now, my project is structured as a library that implements a simple interpreter. I also have a very short Main file which needs to be build into an executable to call the library. What I want to do is:
1) compile the library and expose some of the modules
2) compile the executable
I have a cabal file that works and seems to do this. The problem is that when it compiles the executable it recompiles all the modules which have already been compiled in step (1). I don't quite understand why it does this - is there any way to stop it, short of creating two separate cabal files?
I don't really want to create two separate cabal files, because cabal doesn't seem to like having both the cabal files in the same directory, and I don't really want to set up a separate project directory for the second step, since it basically just amounts to compiling a single file.
cabal-version: >= 1.6
build-type: Simple
name: HaSC
version: 0.2.3
license: OtherLicense
category: Language
author: Chris B
maintainer: Chris B
copyright: Chris B 2010 - 2011
synopsis: (HA)skell (S)ound (C)hange applier (HaSC) library
description: HaSC implements a little language for applying sound changes to words
homepage: http://www.chrisdb.me.uk/redmine/projects/haskell-sound-change
stability: Alpha
data-files: doc/HaSCDoc.pdf
license-file: LICENSE
library
build-depends:
base >= 4.3,
containers >= 0.3,
parsec >= 3,
parallel >= 3.1,
deepseq >= 1.1,
mtl >= 1.1,
transformers >= 0.2,
text >= 0.10,
text-icu >= 0.6.3,
pretty >= 1,
directory >= 1.1,
filepath >= 1.2
hs-source-dirs: src
exposed-modules: HaSC.IO.Disk,
HaSC.IO.Memory,
HaSC.Exec
other-modules: HaSC.AST,
HaSC.IO,
HaSC.IdentMap,
HaSC.Parse,
HaSC.Regex,
HaSC.Representation,
HaSC.Transformations,
HaSC.Search,
HaSC.State
executable HaSC
GHC-Options: -rtsopts
hs-source-dirs: src
main-is: Main.hs
In your executable section, add the library in Build-Depends so that the executable depends on the library.
There's a small gotcha, though: You also have to move the Main.hs of the executable (and any other source files specific to the executable) to a different subdirectory and specify a different Hs-Source-Dirs so that it doesn't pick up the library modules by being in the same folder.
executable HaSC
Build-Depends: HaSC
Main-Is: Main.hs
Hs-Source-Dirs: foo -- Directory you moved Main.hs to
For this to work, you will need to specify Cabal-Version >= 1.8. See Cabal ticket #89 for the details.

Resources