{"id":8403,"library":"pcpp","title":"PCPP: A C99 Preprocessor","description":"PCPP is a pure Python implementation of a C99 preprocessor. It's designed to preprocess C and C++ source code, handling directives like `#include`, `#define`, and conditional compilation. A key use case is for processing header-only C++ libraries into single-file includes and for integration with documentation tools like Doxygen. The library is actively maintained, though with an infrequent release cadence, with the latest significant update in late 2021.","status":"active","version":"1.30","language":"en","source_language":"en","source_url":"https://github.com/ned14/pcpp","tags":["C preprocessor","C99","preprocessing","compiler tools","build tools","macros","header files"],"install":[{"cmd":"pip install pcpp","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"Used for parsing C preprocessor expressions with its yacc module, fundamental to PCPP's core functionality.","package":"ply","optional":false}],"imports":[{"note":"The primary class for C preprocessor operations.","symbol":"Preprocessor","correct":"from pcpp.preprocessor import Preprocessor"}],"quickstart":{"code":"from pcpp.preprocessor import Preprocessor\nimport io\n\n# Example C code as a string\nc_code = '''\n#define MY_MACRO \"Hello, World!\"\n#define VERSION 10\n\n#if VERSION > 5\nconst char* message = MY_MACRO;\n#else\nconst char* message = \"Old version\";\n#endif\n\nint main() {\n    printf(\"%s\\n\", message);\n    return 0;\n}\n'''\n\n# Create a Preprocessor instance\np = Preprocessor()\n\n# Define additional macros (optional)\np.define(\"DEBUG\")\n\n# Prepare input stream (from string or file)\ninput_stream = io.StringIO(c_code)\n\n# Parse and preprocess the input\np.parse(input_stream)\n\n# Get the preprocessed output\noutput = p.stream()\n\n# You can iterate through the tokens or get the full string output\nprocessed_code = ''.join(str(x) for x in output)\n\nprint(processed_code)\n\n# Expected output for VERSION=10 and DEBUG defined:\n# const char* message = \"Hello, World!\";\n#\n# int main() {\n#     printf(\"%s\\n\", message);\n#     return 0;\n# }\n","lang":"python","description":"This quickstart demonstrates how to instantiate the `Preprocessor` class, define custom macros, feed it C source code, and retrieve the preprocessed output. The `parse` method takes a file-like object, and `stream` returns an iterator of tokens which can be joined to form the final string."},"warnings":[{"fix":"If relying on `#line` directives for debugging or tools, ensure your build system or downstream tools are aware of and correctly interpret relative paths. Adjust expectations for `__FILE__` and `__LINE__` macros accordingly.","message":"In v1.21, the paths emitted by `pcpp` into `#line` directives became relative to the working directory where the `Preprocessor` was initialized. Previously, these might have been absolute or behaved differently.","severity":"breaking","affected_versions":">=1.21"},{"fix":"When using the command-line tool, use the `--compress` option. When using the API, check for a corresponding `compress` attribute or method on the `Preprocessor` instance (consult the documentation for exact API usage).","message":"Starting with v1.20, `pcpp` no longer collapses whitespace in the output by default. If your application expects compact output, you must explicitly enable compression.","severity":"gotcha","affected_versions":">=1.20"},{"fix":"Use the `passthru_magic_macros` option when initializing `Preprocessor` or the `--passthru-magic-macros` command-line argument if you want these macros to remain unexpanded in the output.","message":"Special C preprocessor 'magic' macros like `__DATE__`, `__TIME__`, `__FILE__`, `__LINE__`, and `__COUNTER__` have specific handling. By default, `pcpp` might expand these, but if you need them passed through unexpanded (e.g., for Doxygen), specific options are required.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Ensure the library is installed using pip: `pip install pcpp`","cause":"The 'pcpp' library is not installed in the current Python environment.","error":"ModuleNotFoundError: No module named 'pcpp'"},{"fix":"Add the directory containing the header file to the preprocessor's include paths using `p.add_path('/path/to/headers')` or the `-I` command-line option. Relative paths are often resolved from the current working directory, but explicit paths are robust.","cause":"The preprocessor could not find an included file (e.g., via `#include <some_header.h>` or `#include \"some_header.h\"`) because its directory was not added to the search paths.","error":"FileNotFoundError: No such file or directory: 'some_header.h'"},{"fix":"Review the expression for correct C99 preprocessor syntax. Ensure all macros used in the expression are defined or handle undefined macros gracefully. PCPP v1.30 improved expression evaluation with a yacc-based parser, fixing many issues from older `eval()`-based approaches.","cause":"The C preprocessor expression within an `#if` or `#elif` directive is malformed or uses constructs not supported by C99, leading to a parsing error.","error":"SyntaxError: invalid preprocessor expression in #if/#elif directive"}]}