I see this used often to make modules compatible with GHC and Hugs, but google is not helping me learn more about it.
What can I put inside the conditional? Can I make parts of a module conditional on what version of 'base' is in use?
EDIT 3/2017: This is a great resource: https://guide.aelve.com/haskell/cpp-vww0qd72
The GHC documentation has a section relating to the C pre-processor that documents some of the predefined
pre-processor macros.
The Cabal documentation has a section relating to conditional compilation that gives an example relating to base. If you are writing a portable package, you should be using Cabal, anyway.
In addition to the very useful flags defined by GHC (OS, architecture, etc), when using cabal other flags and macros are defined.
Check Package Versions
Here's a use from crypto-api that checks the version of the tagged package being used:
#if MIN_VERSION_tagged(0,2,0)
import Data.Proxy
#endif
Custom CPP Defines Based on Cabal Flags
You can define CPP symbols dependent on cabal flags. Here's an (unnecessarily complex) example from pureMD5 (from the .cabal file):
if arch(i386) || arch(x86_64)
cpp-options: -DFastWordExtract
Inside the .hs module you can then use #ifdef, for example:
#ifdef FastWordExtract
getNthWord n b = inlinePerformIO (unsafeUseAsCString b (flip peekElemOff n . castPtr))
#else
... other code ...
#endif
For more information you can see the Cabal users guide. This page has the "conditional compilation" information you're probably looking for.
#ifdef and friends are used by the C preprocessor (CPP). They provide a way to compile code conditionally. You can enable the use of the CPP by adding the pragma {-# LANGUAGE CPP #-} on top of a file.
Many programs that deal with Haskell code set some macros for the preprocessor (eg. GHC sets __GLASGOW_HASKELL__ to the version of GHC), so one can conditionally compile code, for instance to use different properitary libraries for Hugs and GHC.
If you run your Haskell compiler with the -cpp option, it will first preprocess the source files with the CPP (C Pre Processor).
Take a look at the section 4.11.3. Options affecting the C pre-processor here.
Related
The CPP extensions allows conditional compilation, e.g.
{-# LANGUAGE CPP #-}
#ifdef DEBUG
-- some debug code
#endif
It works fine, of course, but it's quite clumsy and non-idiomatic. Is there really no other mechanism to achieve conditional compilation?
(The specific case where I really would like to use it is the Text.Megaparsec.Debug.dbg function. The parse trail it produces is really useful, but the source code gets littered with #ifdef...#endif noise which makes it all rather unreadable. A wrapper function at the top would remove most of the noise, but I'm wondering nonetheless.)
A lightweight solution is to only use CPP once to define a boolean which can then be used in regular Haskell code:
#ifdef DEBUG
#define debug True
#else
#define debug False
#fi
or a macro if you don't even want the debug code to go through typechecking.
Another way to do conditional compilation without CPP is to change the source of modules at the package level, though I don't know any real example of this.
Create two modules with the same name debug/Debug.hs and nodebug/Debug.hs, both exporting, for example, a boolean debug :: Bool.
In the package configuration, add a flag to select between debug/ and nodebug/.
flag debug
description: debug mode
default: False
manual: True
library
...
if flag(debug)
hs-source-dirs: debug
else
hs-source-dirs: nodebug
Now you can build the library with -f +debug to enable debugging.
I am trying to generate documentations for a github library using haddock. Here's the code I entered:
$ find -name '*.hs' | xargs haddock --html -o docs
src/Reflex/Dom/Xhr.hs:154:0:
error: missing binary operator before token "("
#if MIN_VERSION_aeson(1,0,0)
^
Then I looked up the relevant section of my source code Xhr.hs line 154:
import Data.Aeson
#if MIN_VERSION_aeson(1,0,0)
import Data.Aeson.Text
#else
import Data.Aeson.Encode
#endif
I didn't know #if, #else and #endif were part of Haskell but I could guess the meaning. Depending on the version, the code should import either Aeson.Text or Aeson.Encode. Just in case, I looked up the version:
$ ghc-pkg list | grep aeson
aeson-0.11.3.0
This was enough to give haddock difficulty. The info pages get sent to a folder called docs which contains a few empty html files waiting to be populated with the details of the Reflex.Dom library.
That code uses -cpp. Preprocessor directives are not part of the usual Haskell language. In order to correctly parse that code, you need to specify additional options to Haddock:
2.1. Using literate or pre-processed source
Since Haddock uses GHC internally, both plain and literate Haskell sources are accepted without the need for the user to do anything. To use the C pre-processor, however, the user must pass the the -cpp option to GHC using --optghc. [emphasis mine]
There are two problems, though. C preprocessor macro expansion you've posted will only work with GHC 8.0 (or later) if the package is exposed. It should, however, work with cabal haddock or stack haddock regardless of GHC's version. The latter variants are recommended if you try to build the documentation of a cabal/stack package, by the way.
If you still know what you're doing, use haddock --optghc=-cpp.
In a Haskell project, I am using a dependency which I know contains type error. But that's actually fine as I never call this code.
So I want to enable defer-type-errors but only for that dependent package.
Is there a way to scope that compiler instruction somewhere (stack ? cabal?)
If you really have to you can set ghc options per package in stack.yaml, namely:
ghc-options:
your_package_name: -fdefer-type-errors
I'm not sure whether it's compatible with ghcjs.
But please be sure to make the users of your package aware, maybe include a disclaimer in the document in big bold fonts.
I'm building a small haste project where I want to use Elasticsearch. However, bloodhound which seems like the library to go for for elasticsearch in haskell depends indirectly on template-haskell - which isn't supported by haste. Now, I don't need to call elastic from the client, so I don't need bloodhound in haste, but I need to be able to call it from within the same code base as haste is built to use the same code for server and client side. I guess I somehow could have separate client and server side implementations but I really like the haste way.
How can I have calls to dependencies that only exist on the server side in haste?
Preprocessor can be used for this purpose. Haste defines __HASTE__ macro so it should be enough to wrap your code in conditional statement:
{-# LANGUAGE CPP #-}
main = do
#ifdef __HASTE__
print "haste!"
#endif
#ifndef __HASTE__
print "not haste!"
#endif
print "everybody"
Don’t forget to enable C preprocessor extension using {-# LANGUAGE CPP #-} pragma.
You can also achieve similar effect in your ‘.cabal’ file:
Build-Depends:
bytestring >= 0.9.2.1
if flag(haste-inst)
Build-Depends:
base == 4.6.0.1,
array == 0.4.0.1
else
Build-Depends:
base,
array,
random,
websockets >= 0.8
(source https://github.com/valderman/haste-compiler/blob/0.4/libraries/haste-lib/haste-lib.cabal#L63)
Note that the haste-inst flag has been renamed to haste-cabal in the latest development version of Haste.
A potential solution I've thought about is to import a "Shared" module with to different implementations, one client/Shared.hs and one server/Shared.hs and then include one of the implementations using the -i option. So -iclient for haste and -iserver for ghc.
I can't test this at the moment though so I'll have to get back to it.
I've got the following situation:
Library X is a wrapper over some code in C.
Library A depends on library X.
Library B uses Template Haskell and depends on library A.
GHC bug #9010 makes it impossible to install library B using GHC 7.6. When TH is processed, GHCi fires up and tries to load library X, which fails with a message like
Loading package charsetdetect-ae-1.0 ... linking ... ghc:
~/.cabal/lib/x86_64-linux-ghc-7.6.3/charsetdetect-ae-1.0/
libHScharsetdetect-ae-1.0.a: unknown symbol `_ZTV15nsCharSetProber'
(the actual name of the “unknown symbol” differs from machine to machine).
Are there any workarounds for this problem (apart from “don't use Template Haskell”, of course)? Maybe library X has to be compiled differently, or there's some way to stop it from loading (as it shouldn't be called during code generation anyway)?
This is really one of the main reasons that 7.8 switched to dynamic GHCi by default. Rather than try to support every feature of every object file format, it builds dynamic libraries and lets the system dynamic loader handle them.
Try building with the g++ option -fno-weak. From the g++ man page:
-fno-weak
Do not use weak symbol support, even if it is provided by the linker. By default, G++ will use weak symbols if they are available. This option exists only for testing, and should not be used by end-users; it will result in inferior code and has no benefits. This option may be removed in a future release of G++.
There is another issue with __dso_handle. I found that you can at least get the library to load and apparently work by linking in a file which defines that symbol. I don't know whether this hack will cause anything to go wrong.
So in X.cabal add
if impl(ghc < 7.8)
cc-option: -fno-weak
c-sources: cbits/dso_handle.c
where cbits/dso_handle.c contains
void *__dso_handle;