What is cpphs?
How do I use it?
Differences to cpp
cpphs as a library

What is cpphs?

cpphs is a liberalised re-implementation of cpp, the C pre-processor, in Haskell.

Why re-implement cpp? Rightly or wrongly, the C pre-processor is widely used in Haskell source code. It enables conditional compilation for different compilers, different versions of the same compiler, and different OS platforms. It is also occasionally used for its macro language, which can enable certain forms of platform-specific detail-filling, such as the tedious boilerplate generation of instance definitions and FFI declarations. However, there are two problems with cpp, aside from the obvious aesthetic ones:

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.

This version of the C pre-processor is pretty-much feature-complete, and compatible with the -traditional style. It has two main modes:

In --nomacro mode, cpphs performs only conditional compilation actions, namely #include's, #if's, and #ifdef's are processed according to text-replacement definitions and macro expansions (both command-line and internal). In full compatibility mode (the default), textual replacements and macro expansions are also processed in the remaining body of non-cpp text.

Source language features:
#ifdef simple conditional compilation
#if the full boolean language of defined(), &&, ||, ==, etc.
#elif chained conditionals
#define in-line definitions (text replacements and macros)
#undef in-line revocation of definitions
#includefile inclusion
#line line number directives
#pragma cpp pragmas (ignored)
\\n line continuations within all # directives
/**/ token catenation within a macro definition
## ANSI-style token catenation
# ANSI-style token stringisation
__FILE__special text replacement for DIY error messages
__LINE__special text replacement for DIY error messages
__DATE__special text replacement
__TIME__special text replacement

Macro expansion is recursive. Redefinition of a macro name does not generate a warning. Macros can be defined on the command-line with -D just like textual replacements. Macro names are permitted to be Haskell identifiers e.g. with the prime ' and backtick ` characters, which is slightly looser than in C, but they still may not include operator symbols.

Numbering of lines in the output is preserved so that any later processor can give meaningful error messages. When a file is #include'd, cpphs inserts #line directives for the same reason. Numbering should be correct even in the presence of line continuations. If you don't want #line directives in the final output, use the --noline option, or if you would prefer them in {-# LINE #-} Haskell pragma format, use the --linepragma option.

Any syntax error in a cpp directive gives a warning message to stderr. Failure to find a #include'd file also produces a warning to stderr. In both cases, processing continues on the rest of the input.

How do I use it?

Usage: cpphs  [ filename | -Dsym | -Dsym=val | -Ipath ]+  [-Ofile]
              [--nomacro] [--noline] [--linepragma] [--nowarn] [--pragma]
              [--strip] [--strip-eol]
              [--text] [--hashes] [--layout] [--unlit]
              [ --cpp compatopts ]
       cpphs --version                                             

You can give any number of filenames on the command-line. The results are catenated on standard output. (Macro definitions in one file do not carry over into the next.) If no filename is given, cpphs reads from standard input.

Note: if you wish to use cpphs as a replacement for gcc's cpp in conjunction with the ghc compiler then the extra options you need to give to ghc are these:

  -cpp  -pgmPcpphs  -optP--cpp

-Dsym define a textual replacement (default value is 1)
-Dsym=val define a textual replacement with a specific value
-Dsym(args)=val define a macro with arguments
-Ipath add a directory to the search path for #include's
-Ofile specify a file for output (default is stdout)
--include=file #include the given file at the start of the input
--nomacro only process #ifdef's and #include's, do not expand macros
--noline remove #line droppings from the output
--linepragma convert #line droppings into {-# LINE #-} format
--nowarn suppress messages from missing #include files, or #warning
--pragma retain #pragma in the output (normally removed)
--strip convert traditional C-style comments (not eol //) to whitespace, even outside cpp directives
--strip-eol convert modern C-style comments (including /**/ and //) to whitespace, even outside cpp directives
--hashes recognise the ANSI # stringise operator, and ## for token catenation, within macros
--text treat input as plain text, not Haskell code
--layout preserve newlines within macro expansions
--unlit unlit literate source code
--cpp compatopts accept standard cpp options: -o, -x, -ansi, -traditional, -P, -C, -A, etc
--version report version number of cpphs and stop

There are NO textual replacements defined by default. (Normal cpp usually has definitions for machine, OS, etc. You can easily create a wrapper script if you need these.) The search path is searched in order of the -I options, except that the directory of the calling file, then the current directory, are always searched first. Again, there is no default search path (unless you define one via a wrapper script).


Current stable version:

cpphs-1.17, release date 2013.08.16
By HTTP: .tar.gz, Hackage.


The current darcs repository of cpphs is available at

    darcs get http://code.haskell.org/cpphs
(Users on Windows or MacOS filesystems may need to use the --partial flag.) What's new, over and above the latest stable release?

Older versions:

cpphs-1.16, release date 2013.01.22
By HTTP: .tar.gz, Hackage.

cpphs-1.15, release date 2012.11.30
By HTTP: .tar.gz, Hackage.

cpphs-1.14, release date 2012.07.11
By HTTP: .tar.gz, Hackage.

cpphs-1.13, release date 2011.09.26
By HTTP: .tar.gz, Hackage.

cpphs-1.12, release date 2011.06.26
By HTTP: .tar.gz, Hackage.

cpphs-1.11, release date 2010.01.31
By HTTP: .tar.gz, .zip, Hackage.

cpphs-1.10, release date 2010.01.30
By HTTP: .tar.gz, .zip,

cpphs-1.9, release date 2009.09.07
By HTTP: .tar.gz, .zip.

cpphs-1.8, release date 2009.08.06
By HTTP: .tar.gz, .zip.

cpphs-1.7, release date 2009.06.22
By HTTP: .tar.gz, .zip.

cpphs-1.6, release date 2008.10.09
By HTTP: .tar.gz, .zip.

cpphs-1.5, release date 2007.06.05
By HTTP: .tar.gz, .zip. Windows binary,

cpphs-1.4, release date 2007.04.17
By HTTP: .tar.gz, .zip.

cpphs-1.3, release date 2006.10.09
By HTTP: .tar.gz, .zip, Windows binary.

cpphs-1.2, release date 2006.05.04
By HTTP: .tar.gz, .zip, Windows binary.

cpphs-1.1, release date 2005.10.14
By HTTP: .tar.gz, .zip.

cpphs-1.0, release date 2005.10.05
By HTTP: .tar.gz, .zip.

cpphs-0.9, release date 2005.03.17
By HTTP: .tar.gz, .zip.

cpphs-0.8, release date 2004.11.14
By HTTP: .tar.gz, .zip.

cpphs-0.7, release date 2004.09.01
By HTTP: .tar.gz, .zip.

cpphs-0.6, release date 2004.07.30
By HTTP: .tar.gz, .zip.

cpphs-0.5, release date 2004.06.07
By HTTP: .tar.gz, .zip.

cpphs-0.4, release date 2004.05.19
By HTTP: .tar.gz, .zip.

cpphs-0.3, release date 2004.05.18
By HTTP: .tar.gz, .zip.

Fix recursive macro expansion bug. Added option to strip C comments. Added option to recognise the # stringise operator.

cpphs-0.2, release date 2004.05.15
By HTTP: .tar.gz, .zip.

Implements textual replacement and macro expansion.

cpphs-0.1, release date 2004.04.07
By HTTP: .tar.gz, .zip.

Initial release: implements conditional compilation and file inclusion only.

Building instructions

To build cpphs, use

    hmake cpphs [-package base]
    ghc --make cpphs [-o cpphs]
    mv cpphs.hugs cpphs	# a simple runhugs script

You will notice that the command-line arguments for cpphs are not the same as for the original cpp. If you want to use cpphs as a completely drop-in replacement for the real cpp, that is, to accept the same arguments, and have broadly the same behaviour in response to them, then use the --cpp compatibility option as the first commandline flag.

Differences from cpp

In general, cpphs is based on the -traditional behaviour, not ANSI C, and has the following main differences from the standard cpp.


Macro definition language

cpphs as a library

You can use cpphs as a library from within a Haskell program. The main interface is in Language.Preprocessor.Cpphs. Haddock documentation is here. To make the library available to your haskell compiler, you must install the cpphs package using Cabal.


I am interested in hearing your feedback on cpphs. Bug reports especially welcome. You can send feature requests too, but I won't guarantee to implement them if they depart much from the ordinary cpp's behaviour. Please mail

Copyright: © 2004-2012 Malcolm Wallace, except for ParseLib (Copyright © 1995 Graham Hutton and Erik Meijer)

License: The library modules in cpphs are distributed under the terms of the LGPL (see file LICENCE-LGPL for more details). If that's a problem for you, contact me to make other arrangements. The application module 'cpphs.hs' itself is GPL (see file LICENCE-GPL). If you have a commercial use for cpphs and find the terms of the (L)GPL too onerous, you can instead choose to distribute unmodified binaries (not source), under the terms of LICENCE-commercial

This software comes with no warranty. Use at your own risk.