How can I have a conditional on cabal? - haskell

I have a Haskell library which exports several modules. I compile that library with both GHC and GHCJS. I'm using stack to build the library. One of those modules depends on reflex-dom. The issue is that I am not able to compile reflex-dom on GHC due to not being able to link gtk+3 on OSX. As such, I'd like to exclude that library if the compiler is GHC. How can I achieve that?
exposed-modules:
MyLib.Foo
MyLib.Bar
MyLib.App.Backend.Reflex
MyLib.App.Backend.Gloss
...
build-depends:
base ...
reflex-dom >= 0.2 && <0.3

While you may not want to do this, the way to do this is described in the "configurations" section of the cabal user manual:
https://www.haskell.org/cabal/users-guide/developing-packages.html#configurations
In particular, you should be able to write the relevant sections as such:
exposed-modules:
MyLib.Foo
MyLib.Bar
MyLib.App.Backend.Reflex
MyLib.App.Backend.Gloss
if !impl(ghc)
exposed-modules:
OtherModule
build-depends: etc, etc, etc
if !impl(ghc)
build-depends: etc1, etc2

Related

Exposing internal modules to tests in Cabal

I'm contributing to an open source project which defines its project setup in a cabal file that looks like this (omitting lots of properties that are not relevant for this problem):
library
hs-source-dirs: src
build-depends:
base >= 4.9 && < 5,
some-other-deps
exposed-modules:
Data.Foo.Bar,
Data.Foo.Baz
other-modules:
Data.Foo.Bar.Internal
test-suite test
hs-source-dirs:
tests
build-depends:
foo-library
other-modules:
Foo.Bar.Tests,
Foo.Baz.Tests
Now, in order to test the feature I'm adding, I want the tests to have access to the Data.Foo.Bar.Internal module, but since it's hidden in the library, I can't access it from the tests.
I looked at the cabal docs which suggested adding a third component - an internal library (unfortunately not linkable, but search for "internal libraries"). If I understand the documentation correctly, I should be able to do something like this:
library foo-internal
hs-source-dirs: src
build-depends:
base,
some-other-deps
exposed-modules:
Data.Foo.Bar.Internal
library
hs-source-dirs: src
build-depends:
base >= 4.9 && < 5,
foo-internal,
some-other-deps
exposed-modules:
Data.Foo.Bar,
Data.Foo.Baz
test-suite test
hs-source-dirs:
tests
build-depends:
foo-library,
foo-internal
other-modules:
Foo.Bar.Tests,
Foo.Baz.Tests
but running stack build here gives me warnings that Data.Foo.Bar.Internal "should be added to exposed-modules or other-modules in ./foo.cabal", and then a build error in the test that seems to be caused by failed unification (it points to a function argument for a function defined in the library, says that its type must be Data.Foo.Bar.Internal.Qux defined in package foo, and that the type foo:Data.Foo.Bar.Internal.Qux don't match).
How can I expose internal modules to the test suite, without exposing them also to consumers of the library?
As mentioned in the comments, different components (internal libraries, executables) should have modules under different roots.
This is a recurrent point of confusion. For another example: https://stackoverflow.com/a/6711739/6863749
There is an open ticket on Cabal's issue tracker about clarifying this with a suitable warning; it's apparently non-trivial to detect this situation reliably because it overlaps with legitimate use cases: https://github.com/haskell/cabal/issues/5335

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.*

plugins package unknown symbol when using cabal

I'm messing around with the plugins package however I bumped into a problem.
Here's the code:
Util/Header.hs
module Util.Header(PT(..)) where
data PT a = PT a deriving Show
Plug.hs
module Plug(helloPlugin) where
import Util.Header
helloPlugin :: PT Int
helloPlugin = PT 1
Main.hs
module Main where
import Util.Header
import System.Plugins
main :: IO ()
main = do
mv <- load "Plug.o" ["."] [] "helloPlugin"
case mv of
LoadFailure msg -> print msg
LoadSuccess _ v -> print $ show (v :: PT Int)
This all works fine then compiling with ghc. Building with Cabal works fine as well, but when I run the executable I get this error:
plugintest: /home/kevin/.cabal/lib/plugins-1.5.4.0/ghc-7.6.3/HSplugins-1.5.4.0.o: unknown symbol `ghczm7zi6zi3_ErrUtils_zdsinsertzuzdsgo5_info'
plugintest: user error (resolvedObjs failed.)
My very minimalistic cabal file:
name: plugintest
version: 0.1.0.0
license-file: LICENSE
build-type: Simple
cabal-version: >=1.8
library
hs-source-dirs: src
exposed-modules: Util.Header
build-depends: base ==4.6.*, plugins ==1.5.*
executable plugintest
main-is: Main.hs
build-depends: base ==4.6.*, plugins ==1.5.*, plugintest == 0.1.0.0
hs-source-dirs: src
Now I assume the problem is that it can't find the "ErrUtils" module which is part of the ghc package installed in /usr/lib/ghc-7.x.x.
Since it's using cabal it'll use the $HOME/.cabal/lib/ instead.
Now I obviously wouldn't want to use /usr/lib if I wanted to make it distributable. Sadly I'm not very familiar with how packages are managed nor am I familiar with the plugins package.
I have a feeling this is extremly nooby but I wasn't able to find a solution myself.
So a few questions:
How can I get my dependencies to work in a way to make this distributable?
It seems I'll need to know beforehand what my Plugin.o files will depend on before actually being able to use them (If I understand correctly).
Is there a way to package a .o files that I wouldn't have to worry about this problem? (Sorry if this question is too vague, feel free to ignore)
Thanks in advance!
Ok, so I had the exact same problem.
Here is a workaround I found
Change the load call to
load "Plug.o" [".","dist/build/plugintest/plugintest-tmp"] [] "testplugin"
Make sure you compile the thing with -c or by using the "make" library from plugins.
Quite annoyed by this... The error suggests it is having issues linking against the standard libs, so why does showing it these .o files fix it?
Anyways, this worked for me, and didn't require a ton of mucking around with .cabal files.
You must declare your exported- and other- modules in order for Cabal to package them all together. For instance (from https://github.com/tel/happstack-heroku-test)
name: hktest -- note the name here names
-- the *library* which is a package name
-- in scope when building the executable
...
library
exposed-modules:
HKTest
other-modules:
-- there aren't any, but there could be some
build-depends: base >= 4.6 && <4.7
...
, mtl >= 2.1.2
hs-source-dirs: src
executable server
main-is: Server.hs
other-modules:
-- there might be some use to having these here,
-- but they'll be harder to get into GHCi, so I wouldn't
-- recommend it---just put them in the library part
build-depends: base >=4.6 && <4.7
, hktest -- note that I grab all the hktest
-- modules here
hs-source-dirs: exe
If I leave out one of those modules I'll likely get a build error as Cabal compiles files which expect to be able to find symbols that haven't been packaged.
In your case, since you're building an executable, the common pattern exemplified above is to put all of your code into a library and then have the executable side depend upon that library. For instance, in this example the complete text of exe/Server.hs is
module Main where
import qualified HKTest as HK
main :: IO ()
main = HK.main

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.

Replace compiler when building Haskell project with Cabal

Is it possible somehow to configure cabal project to use different compiler than GHC? Additional is it possible to control this by some flags?
I want to compile my project with GHC or Haste (to JavaScript) based on some compilation flags.
It would be ideal if I could set my cabal configuration or my custom script to do something like:
-- target JS
cabal configure --target=js
cabal build
-- target Native
cabal configure --target=native
cabal build
To build a Cabal project with either GHC or Haste, use the cabal binary for the former, and haste-inst (comes with haste) for the latter.
To have conditional code in in your modules, add {-# LANGUAGE CPP #-} and use #ifdef __HASTE__, which will only be defined by haste, but not by GHC. Note that __GLASGOW_HASKELL__ is defined in both cases (which makes sense, as haste builds on GHC for large parts of the compilation). So you would use it like
{-# LANGUAGE CPP #-}
module Module where
compiler :: String
#ifdef __HASTE__
compiler = "haste"
#else
compiler = "GHC"
#endif
Theoretically, for conditional settings in the Cabal file something like this should work:
library
exposed-modules:
Module
if impl(ghc)
exposed-modules:
Module.GHC
if impl(haste)
exposed-modules:
Module.GHC
build-depends: base ==4.6.*
but it seems that even with haste-inst, impl(ghc) is true; bug report is filed.
While it's currently not possible to use impl(haste) in your cabal files, you can now check for flag(haste-inst) to see if your package is being built using haste-inst.

Resources