## CPPMiscellaneouseditdelete

With {-# LANGUAGE CPP #-} enabled, .hs files will be processed with C preprocessor before the code is compiled. It's often useful if:

• you need backwards compatibility with an older version of GHC or some library, or you want to avoid compiler warnings
• you are writing code that depends on OS or CPU architecture
• you want to enable some parts of code depending on a flag
• you don't want to bother with Template Haskell and need some easy way to generate code (e.g. repetitive instances)

However, see the Stop (ab)using CPP in Haskell sources post for a discussion of some drawbacks of CPP (and alternatives to it).

# Running CPP

To dump CPP output, do ghc -E file.hs (it'll be saved into file.hspp). There might be a lot of empty lines in the file, so don't forget to scroll.

To just run CPP on a file without using GHC, do either of these:

• gcc -E -traditional - < file.hs (on Linux)
• clang -E -traditional - < file.hs (on macOS)
• cpphs file.hs (for cpphs)

Since Clang is used instead of GCC on macOS, and Clang's preprocessor syntax is slightly different, you should use this command to see whether your code would compile under Clang:

$ghc -pgmP "clang -E -undef -traditional" file.hs # CPP features ## Defining macros #define DOUBLE_QUOTE 34 #define POW(a,b) a ^ (b :: Int) Once a constant/macro is defined, it'll be substituted everywhere in code (except when it's a part of a string or a word). For instance, POW(2,3) will be replaced with 2 ^ (3 :: Int). ## Using constants as flags #ifdef FOO /* or #ifndef to check that a constant is *not* defined */ ... #endif Code inside #ifdef ... #endif will be removed unless FOO is defined (which can be done via .cabal or with a #define earlier in the file). ## Conditionals #if __GLASGOW_HASKELL__ < 710 ... #endif #ifdef FOO is actually a shortcut for #if defined(FOO); with #if you can branch on an arbitrary boolean expression (see the GCC manual for full syntax of conditionals). Also, you can have more than two branches with #elif. Note that #define and other CPP directives can be used inside of #if – it's useful when you're writing your own macros. See the “Standard CPP macros” section in the GHC manual for a full list of macros defined by GHC. # Tricks ## Commas If you need to use a comma in a macro argument, just define a separate macro for the comma: #define COMMA , GEN(a COMMA b COMMA c) ## Concatenation If CPP doesn't understand that a macro should be expanded in some particular place (e.g. if it's a part of a word, or has _ in front of it, etc), you can use /**/: #define U(x) xbar U(foo) <- expanded into “xbar” #define U(x) x/**/bar U(foo) <- expanded into “foobar” on GCC or “foo bar” on Clang Note that if you don't want a space there, cpphs is your only bet. # Workarounds There are three main reasons why code with CPP might not work as expected: 1. You used #, ## or __VA_ARGS__. GHC runs CPP in traditional mode, which disables all advanced features. 2. OS differences – Linux uses GCC and macOS uses Clang, which are slightly incompatible. Either read Differences between GCC and Clang, or consider using cpphs if you don't want to bother. 3. You used something that CPP doesn't support well, like: • #-} on a separate line without space in front of it. • Single or double quotes – CPP tries to handle them smartly and fails. • Multiline strings (e.g. "foo\ and \bar" on two separate lines). • \ at the end of line (e.g. infix 5 \\) – to fix it, add a comment after \. or press Ctrl+Enter to save Check GHC version other Summary GHC versions currently in use: 7.8 = 708, 7.10 = 710, 8.0 = 800. Do something if GHC is older than 7.10: #if __GLASGOW_HASKELL__ < 710 ... #endif Use different code for GHC 8.0 and older versions: #if __GLASGOW_HASKELL__ >= 800 ... #else ... #endif If you need to check for patch level as well (e.g. detect GHC 8.0.1 but not 8.0.2), you can use a .cabal flag: library ... if impl(ghc == 8.0.1) cpp-options: -DGHC_801 For more info on .cabal flags, see Define a .cabal flag. Summary Check version of a library other Summary Cabal automatically generates macros (MIN_VERSION_<library>) for all libraries your project depends upon. E.g. you can do something if e.g. bytestring is 0.10.4 or newer: #if MIN_VERSION_bytestring(0,10,4) ... #endif If a library has hyphens - in its name, replace them with underscores _: #if MIN_VERSION_template_haskell(2,11,0) ... #endif Summary Define a .cabal flag other Summary Let's say you want to add asserts to your code. First, add a flag to your .cabal file: Flag asserts Description: Turn on asserts Default: False library exposed-modules: ... if flag(asserts) cpp-options: -DASSERTS (It's also possible to define a constant by writing -DFOO=bar.) Now, to enable a flag during compilation, do this (to disable, use -asserts instead of asserts): • Cabal: cabal configure -f asserts • Stack: stack build --flag pkgname:asserts Then you can check for this flag in code: #ifdef ASSERTS ... #endif Summary Define a macro other Summary Macros are useful when you need to write repetitive code but don't want to use Template Haskell (either because it's hard or because you want to avoid the compilation time penalty). For example, monad-control uses macros to generate instances, and GHC uses macros to define shorter function names. The simplest example is defining a synonym for a function: #define FI fromIntegral Now FI can be used anywhere instead of fromIntegral. As mentioned in the introduction, it won't be expanded inside strings or words; still, it might be better to undefine it after use: #undef FI We can define a more complex macro with parameters. For instance, instead of generating lenses with makeLenses we could do it with macros (sometimes it's a necessary evil, like when you want to define lenses for data families): #define MAKE_LENS(field, lens) lens f s = (\y -> s {field = y}) <$> f (field s)

-- | Lens for foo.
foo :: Lens' (SomeFamily Int) Foo
MAKE_LENS(foo, _foo)

(Note that we can't get rid of repetition – foo, _foo – without breaking compatibility with Clang. If you use cpphs or don't need your code to compile on macOS, you can use /**/ to add the underscore instead.)

Finally, you can use \ for longer macros:

#define BASE(M)                           \
instance MonadBaseControl (M) (M) where { \
type StM (M) a = a;                   \
liftBaseWith f = f id;                \
restoreM = return;                    \
{-# INLINABLE liftBaseWith #-};       \
{-# INLINABLE restoreM #-}}

This macro isn't actually multiline, though – it will be expanded into a single line (which is why curly braces were used and there's ; after every line).

Summary
Detect OS
other
Summary

The following variables are defined depending on OS:

• mingw32_HOST_OS – Windows
• darwin_HOST_OS – macOS
• ghcjs_HOST_OS – Javascript (when compiling with GHCJS)
• linux_HOST_OS – Linux (shouldn't be needed most of the time)
• freebsd_HOST_OS – FreeBSD
• netbsd_HOST_OS – NetBSD
• openbsd_HOST_OS – OpenBSD
• solaris_HOST_OS – Solaris

For instance, here's how you can detect macOS:

#ifdef darwin_HOST_OS
...
#endif

Note that despite lots of libraries using #if defined(mingw32_HOST_OS) || defined(__MINGW32__) for detecting Windows, you don't need to do it – just mingw32_HOST_OS will suffice. See this Trac ticket.

Summary
Detect architecture
other
Summary

There are variables for detecting architecture:

• i386_HOST_ARCH – x86
• x86_64_HOST_ARCH – x64
• arm_HOST_ARCH – ARM (there's also arm_HOST_ARCH_PRE_ARMv7)
• powerpc_HOST_ARCH
• sparc_HOST_ARCH
#if defined(i386_HOST_ARCH)
...
#elif defined(x86_64_HOST_ARCH)
...
#else
# error Unsupported architecture
#endif

# error Unsupported architecture will emit an error at the CPP step (and stop compilation) if the architecture isn't one of the above.

Summary
Detect Hlint
other
Summary

Sometimes you want to hide some code from Hlint (for instance, if Hlint's parser doesn't support a particular language feature yet).

You can do it by defining HLINT (e.g. by writing a script like lens does, or just by passing --cpp-define=HLINT to Hlint) and then wrapping code into an #ifndef HLINT section:

#ifndef HLINT
...
#endif
Summary
Detect Int/Word size
other
Summary

You can use CPP to find out whether Int and Word have 32 bits, 64 bits, or (if you're unlucky) some other amount of bits. First you'll have to add #include "MachDeps.h" to the beginning of the file. This makes the WORD_SIZE_IN_BITS variable available:

#if (WORD_SIZE_IN_BITS == 64)
...
#else
...
#endif

There are other constants defined in MachDeps.h as well.

Summary
Use cpphs as the preprocessor
other
Summary

Sometimes it's easier to use cpphs than to fight with GCC's and Clang's differences, idiosyncrasies, etc:

[...] There have always been problems with, for instance, string gaps, and prime characters in identifiers. These problems are only going to get worse.

So, it seemed right to provide an alternative to cpp, both more compatible with Haskell, and itself written in Haskell so that it can be distributed with compilers.

Cpphs handles single quotes and /**/ correctly, doesn't mangle Haddock comments and knows about Haskell's multiline strings.

To use cpphs, you need to add these options to all sections of your .cabal file:

library
...
build-tools: cpphs >= 1.19
ghc-options: -pgmP cpphs -optP --cpp

A warning: Stack will install cpphs automatically, but cabal-install might not (and then you'd have to install it manually). Thus, depending on cpphs isn't recommended for libraries that would be published on Hackage.

If you can't use cpphs because of its modified LGPL license (e.g. in corporate environment where each license has to be vetted by a lawyer), you can use hpp instead.

Summary
base-feature-macros (Hackage)
other
Summary

The base-feature-macros package lets you write some macros more conveniently – e.g. instead of #if MIN_VERSION_base(4,8,0) you can write #if HAVE_FOLDABLE_TRAVERSABLE_IN_PRELUDE, which is much more understandable to a casual reader.

Summary
Differences between GCC and Clang
other
Summary

On Linux and Windows, GCC's CPP is used for preprocessing; on macOS – Clang's CPP. They have some differences, which you have to account for (unless you're using cpphs).

If you're on Linux, use ghc -pgmP "clang -E -undef -traditional" file.hs to check whether your code would compile with Clang. If you use CI (e.g. Travis-CI), you can add it to your .cabal file in the ghc-options section (hidden under a flag) and run your CI builds both with and without the flag.

# Single quotes

Clang is more strict about single quotes than GCC. For instance, this piece of code using -XDataKinds won't be expanded correctly by Clang:

#define X(a) Foo '[a]
X(Int)                         <- expanded into “Foo '[a]”

A workaround is defining a separate macro for ':

#define QUOTE '
#define X(a) Foo QUOTE[a]
X(Int)                         <- expanded into “Foo '[Int]”

If you need to surround something with single quotes, this might help:

#define QUOTE() '
#define QLEFT(a) QUOTE()a
#define Q(a) QLEFT(a)'
Q(Int)                         <- expanded into “'Int'”

# Concatenation

GCC expands the following macro as _foo, but Clang adds a space and produces _ foo:

#define U(x) _/**/x
U(foo)

There is no way to get rid of the space on Clang. Either rewrite your code to not need such tricks, or use cpphs.

Summary