cpphs

A liberalised re-implementation of cpp, the C pre-processor.

LTS Haskell 24.10:1.20.9.1@rev:2
Stackage Nightly 2025-09-15:1.20.10
Latest on Hackage:1.20.10

See all snapshots cpphs appears in

LicenseRef-LGPL licensed by Malcolm Wallace
Maintained by Andreas Abel
This version can be pinned in stack with:cpphs-1.20.10@sha256:0eb819ca1fbcb13ac004cd4577fd177859054bc391834d55129f4fd8f1bda1ce,3051

Module documentation for 1.20.10

Used by 3 packages in nightly-2025-09-15(full list with versions):

Hackage version Stackage LTS version cpphs on Stackage Nightly Cabal build

cpphs

A liberalised re-implementation of cpp, the C pre-processor.

cpphs is a re-implementation of the C pre-processor that is 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 traditional (K&R) pre-processors. Additional features include: a plain-text mode; an option to unlit literate code files; and an option to turn off macro-expansion.

Usage

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

For fuller details, see docs/index.html.

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.

Copyright

(c) 2004-2017 Malcolm Wallace ([email protected])

Licence

These library modules are distributed under the terms of the LGPL. The application module cpphs.hs is GPL.

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

If you have a commercial use for cpphs, and feel the terms of the (L)GPL are too onerous, you have the option of distributing unmodified binaries (only, not sources) under the terms of a different licence (see LICENCE-commercial).

Website

Description see: https://hackage.haskell.org/package/cpphs

Old homepage: https://archives.haskell.org/projects.haskell.org/cpphs/

Changes

Version 1.20.10

Andreas Abel, 2025-09-14

  • Drop support for GHC 7.
  • Remove cabal flag old-locale.
  • Compatibility with {-# LANGUAGE RecordDotSyntax #-} (Lennart Augustsson).
  • Build tested with GHC 8.0 - 9.14 alpha1.

Version 1.20

  • bugfixes for #if defined(FOO) && FOO(a,b)
  • (1.20.1): fix version number
  • (1.20.2): ensure all input/output is UTF8, regardless of locale
  • (1.20.3): detect an absolute windows path with a drive letter in a #include
  • (1.20.4): more windows path handling
  • (1.20.5): revert change in 1.20.4
  • (1.20.6): minor bugfix for crash in obscure corner case
  • (1.20.7): bugfix for windows drive letter in #include
  • (1.20.8): another bugfix for windows drive letter in #include

Version 1.19

  • expose more of the cpphs API
  • allow the static linking exception to the LGPL
  • (1.19.1): don’t warn about trailing comments in #ifdefs
  • (1.19.2): fix build error
  • (1.19.3): bugfix for hlint ticket #161 - interaction of –unlit/–linepragma

Version 1.18

  • better lexing of Template Haskell single quotes (thanks to Stefan Wehr)
  • (1.18.1): fix incomplete pattern match
  • (1.18.2): bugfix for erroneous boolean intepretation of some macro expansions in #if clauses
  • (1.18.3): further rewrites of the #if expression parser
  • (1.18.4): fix the accidental flipping of comment-stripping behaviour with –cpp -traditional flags
  • (1.18.5): fix a bug with windows filepath directory separators in a #include
  • (1.18.6): bugfix to reject a macro usage with different arity than its definition
  • (1.18.7): bugfix to accept a #include with absolute filepath
  • (1.18.8): fix version number
  • (1.18.9): accept #if defined foo as well as #if defined(foo)

Version 1.17

  • recursively evaluate #if expressions after macro expansion (fix)
  • (1.17.1): report the right version with cpphs –version

Version 1.16

  • fix interaction of runCpphsReturningSymTab with –nomacro

Version 1.15

  • Fix the interaction of –nomacro with –strip.
  • Fix the error message received when # appears without a command.

Version 1.14

  • New API to return symbol table after processing.

Version 1.13

  • Accept -U cmdline option for compatibility with cpp.

Version 1.12

  • Allow it to build with ghc-7.2.

Version 1.11

  • API change: runCpphs, cppIfdef, and macroPass are now in the IO monad.

Version 1.10

  • New command-line option: “–linepragma” It converts #line droppings into {-# LINE #-}.

Version 1.9

  • Bugfix for #undef.

Version 1.8

  • Bugfix for off-by-one error in line numbers with –include=file.

Version 1.7

  • Bugfix in interaction of –unlit with \end{code}

Version 1.6

  • New command-line option: “–include=filename”.
  • New command-line option: “–strip-eol” for comment-stripping.
  • Line pragmas can have filenames containing spaces.

Version 1.5

  • Parametrised macro-calls now permitted in #ifdef’s.
  • Recursive textual expansion now permitted in #ifdef’s.
  • Better options-handling when used as a library.
  • Various small bugfixes

Version 1.4

  • Added a “–pragma” option to retain #pragma in the output.
  • Fixed a number of obscure corner cases involving the interaction of multiple features e.g. foo##LINE.
  • Added the “–nowarn” option.

Version 1.3

  • Added a “–cpp” option for drop-in compatibility with standard cpp. It causes cpphs to accept standard cpp flags and translate them to cpphs equivalents. Compatibility options include: -o, -ansi, -traditional, -stdc, -x, -include, -P, -C, -CC, -A. The file behaviour is different too - if two filenames are given on the commandline, then the second is treated as the output location.
  • Fixed a corner-case bug in evaluating chained and overlapping #ifdefs.

Version 1.2

  • Re-arranged the source files into hierarchical libraries.
  • Exposed the library interface as an installable Cabal package, with Haddock documentation.
  • Added the –unlit option, for removing literate-style comments.

Version 1.1

  • Fix the .cabal way of building cpphs.
  • Update the –version reported (forgotten in 1.0, which still reports 0.9)
  • No longer throws an error when given an empty file as input.

Version 1.0

  • Add a compatibility script cpphs.compat, allowing cpphs to act as a drop-in replacement for cpp, e.g. ghc -cpp -pgmP cpphs.compat
  • Place quotes around replacements for special macros FILE, DATE, and TIME.
  • If no files are specified, read from stdin.
  • Ignore #! lines (e.g. in scripts)
  • Parse -D commandline options once only, and consistently with cpp, i.e. -Dfoo means foo=1
  • Fix compatibility with preprocessors like hsc2hs, which use non-cpp directives like #def. They are now passed through to the output with a warning to stderr.

Version 0.9

  • Bugfix for ghc-6.4 -O: flush the output buffer.

Version 0.8

  • Added the –text option, to signify the input should not be lexed as Haskell. This causes macros to be defined or expanded regardless of their location within comments, string delimiters, etc.
  • Shuffle a few files around to make it easier to say ‘hmake cpphs’. There is also now a runhugs script to invoke cpphs nicely.

Version 0.7

  • Enable the FILE, LINE, DATE, and TIME specials, which can be useful for creating DIY error messages.

Version 0.6

  • Recognise and ignore the #pragma cpp directive.
  • Fix beginning-of-file bug, where in –noline mode, a # cpp directive at the top of the file appeared in the output.
  • Fix chained parenthesised boolean exprs in #if, e.g. #if ( foo ) && ( bar )
  • Fix precedence in chained unparenthesised boolean exprs in #if, e.g. #if foo && bar || baz && frob
  • For better compatibility with cpp, and because otherwise there are certain constructs that cannot be expressed, we no longer permit whitespace in a #define between the symbolname and an opening parenthesis, e.g. #define f (f’ id) Previously, this was interpreted as a parametrised macro, with arguments in the parens, and no expansion. Now, the space indicates that this is a textual replacement, and the parenthesised expression is in fact the replacement.

Version 0.5

  • Added a –version flag to report the version number.
  • Renamed –stringise to –hashes, and use it to turn on ## catenation as well.
  • Bugfix for #if 1, previously taken as false.
  • Bugfix for –nolines: it no longer adds extra spurious newlines.
  • File inclusion now looks in the directory of the calling file.
  • Failure to find an include file is now merely a warning to stderr rather than an error.
  • Added a –layout flag. Previously, line continuations in a macro definition were always preserved in the output, permitting use of the Haskell layout rule even inside a macro. The default is now to remove line continuations for conformance with cpp, but the option of using –layout is still possible.

Version 0.4

  • New flag -Ofile to redirect output
  • Bugfix for precedence in #if !False && False
  • Bugfix for whitespace between # and if
  • Bugfix for #define F “blah”; #include F

Version 0.3

  • Bugfix for recursive macro expansion.
  • New flag –strip to remove C comments even outside cpp directives.
  • New flag –stringise to recognise the # stringise operator in macros.

Version 0.2

  • New flag –noline to eliminate #line directives from output.
  • Add symbol-replacement and macro-expansion.
  • New flag –nomacro to turn off symbol/macro-expansion.

2004-Apr-21

  • Now accept multi-line # commands via the \ line continuation operator. The original file line numbering is preserved in the output by some tricky acrobatics.

Version 0.1

  • Initial release.