Is it possible to use cpp preprocessors with haskell stack,
e.g:
{-# LANGUAGE CPP #-}
module MyModule (
main
#ifdef TEST
,functionUnderTest
,functionAlsoUnderTest
#endif
) where ....
with cabal, the following settings in .cabal appear to work:
cpp-options: -DTEST
is it possible to reproduce this with stack?
From the wiki, this answer here on SO and also this github issue
flags
Flags can be set for each package separately, e.g.
flags: package-name:
flag-name: true
Flags will only affect packages in your packages and extra-deps settings. Packages that come from the snapshot global
database are not affected.
Alternatively you can pass a flag on directly when invoking stack with --flag, I assume the syntax would be something like
stack test --flag project:TEST
Related
I'm trying to have a submodule in my program compile conditionally to switch small parts of the code between release builds and development builds.
Currently I'm attempting to use cpphs however when I change the flags passed into GHC to define a variable and change an ifdef statement stack won't recompile those files.
For example, I've got a port number that I want to switch based on which target I have built. The code I have defining this number looks like this.
#ifdef StableRelease
port = 12345
#else
port = 54321
#endif
the stable build has the following options in its cabal file
ghc-options: -threaded -rtsopts -with-rtsopts=-N -pgmP cpphs -optP "-DStableRelease"
When I run stack build though it doesn't seem to actually pre-process the code above.
Does anyone have experience with cpphs or another preprocessing solution?
I would solve this with the help of flags
cppstuf.cabal-file
name: cppstuf
version: 0.1.0.0
...
cabal-version: >=1.10
flag StableRelease {
Description: Stable release settings like port ...
Default: False
}
executable cppstuf
main-is: Main.hs
build-depends: base >=4.9 && <5.00
default-language: Haskell2010
extensions: CPP
if flag(StableRelease) {
GHC-Options: -DSTABLE
}
Main.hs
module Main where
main :: IO ()
main =
#if STABLE
putStrLn "Hello, Haskell!"
#else
putStrLn "Hello, Haskell?"
#endif
and compiling it
stack build
or
stack build --flag cppstuf:stablerelease
Personal Note aside from the answer
I would not use CPP to manage configuration options - either providing command-line options I like optparse-applicative but there is also cmdargs,and or a configuration file I have used configurator for that, but there are several options out there on hackage. One being configurator-ng as #Shersh said - the other one is not being developed anymore.
CPP on the other hand I tend to use for making libraries work across multiple GHC/library versions.
Update - w\ regards to the comment.
If I deliver a program, the operations team should be able to change ports, hostname or handle file location of input files etc. without knowing haskell let alone recompiling a project.
It makes error chasing a lot easier if your production source code does not differ from your development sources, say you would have a postgres db in dev mode, but an oracle in production - you'll never find the oracle specific bug.
For things like optimization levels - I don't mind too much.
But make sure you test multi-threaded stuff properly, I once ran out of file handles because I was opening a lot but not closing fast enough - If your dev-setting is single threaded you'll deliver a bug.
I'm working on a project that's chosen CMake as its build tool. The project is made up of several executables and since a few months back a few of them are written in Haskell. We strongly wish all executables to show the same version number when called as foo --version. Ideally that version should be recorded in one place, and ideally that place should be the top-level CMakeLists.txt (this is where the source for all the other executables get it, via the use of CMake's configure_file function).
Is there some nice way of achieving this?
Some extra information that might be useful:
The source for each executable lives in its own dir, with its own Cabal file.
We use stack to build, and there is a single stack.yaml file that points to all directories with Haskell code.
I thought I'd document the solution I've landed on.
the source changes
I added the CPP language extension and use a macro (VERSION) to chose between a version provided as a CPP macro and the version provided by Cabal:
{-# LANGUAGE CPP #-}
module Main where
import Data.Version
import Text.ParserCombinators.ReadP
.... -- other imports
#ifdef VERSION
#define xstr(s) str(s)
#define str(s) #s
version = fst $ last $ readP_to_S parseVersion xstr(VERSION)
#else
import Paths_<Cabal project name> (version)
#endif
The need for the double-expansion (xstr and str) is explained in the answer to another question.
building
The above code will unfortunately not build with a simple stack build command. This apparently has to do with the default CPP that ghc uses (/usr/bin/gcc) and the flags it passes to it (as I understand it the culprit is -traditional). The solution is to tell ghc to use GNU CPP:
stack build --ghc-options "-pgmP=/usr/bin/cpp -DVERSION=1.2.3"
or as I put it in my CMakeLists.txt (I use ExternalProject to integrate stack into our CMake-based build):
ExternalProject_Add(haskell-bits
...
BUILD_COMMAND cd <SOURCE_DIR>
&& ${HaskellStack_EXE} --local-bin-path <BINARY_DIR> --install-ghc
install --ghc-options "-pgmP=/usr/bin/cpp -DVERSION=${<CMake proj name>_VERSION}"
...
)
I'm trying to use haskell for scripting in the pattern specified here on the "Script interpreter" section:
https://haskell-lang.org/tutorial/stack-script
When I have comments like this in my script after the shebang:
#!/usr/bin/env stack
{- stack
--resolver nightly-2016-11-26
--install-ghc
runghc
--package http-conduit
-}
{-# LANGUAGE OverloadedStrings #-}
I know I can safely say run:
$ stack myfile.hs
And it correctly picks up the resolver version I specified I need.
However, if I also try to build my script, to have the best of both worlds in scripting for development while I figure things out, and compilation once I'm more sure...
username#myhost:~/$ stack exec -- ghc myfile.hs && ./myfile
Run from outside a project, using implicit global project config
Using resolver: lts-7.10 from implicit global project's config file: /home/username/.stack/global-project/stack.yaml
That will error out because it's using resolver 'lts-7.10' from my global config instead of 'nightly-2016-11-26' even though my comments after the shebang specify a specific, non-global resolver to use.
While I know I could run ghc above and explicitly call --resolver on the command line, I would prefer if this were picked up from what's within the file itself. Is this possible?
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.
Suppose I have a library packaged and built using Cabal, and some module Internal is not in my cabal file's Exposed-modules. Does it then make any difference if I specify a pragma
{-# OPTIONS_HADDOCK hide #-}
at the top of Internal.hs, or is it already automatically hidden according to Haddock?
If it does make a difference, what effect does it have?
It does make a difference if the haddocks of the package are created with the --internal flag to cabal haddock.
$ cabal help haddock
Usage: cabal haddock [FLAGS]
Flags for haddock:
-h --help Show this help text
-v --verbose[=n] Control verbosity (n is 0--3, default verbosity
level is 1)
<snip>
--executables Run haddock for Executables targets
--internal Run haddock for internal modules and include all
symbols
<snip>
If the haddocks are created without the --internal flag, the hide module attribute has no effect: no documentation is created for the module anyway.
If --internal is given, then documentation is created for non-exposed modules except those that specify the hide attribute.
In other words, documentation is generated if hide is not set and either --internal is specified or the module is exported.
The use of --internal for cabal haddock can be specified with cabal install --haddock-internal, or when manually invoking cabal haddock, or with the runhaskell ./Setup.hs ... interface.
Most people just run cabal install with the default options, so only few would observe the difference.