### Install cxxheaderparser Source: https://github.com/robotpy/cxxheaderparser/blob/main/README.md Install the library using pip. Requires Python 3.6+. ```bash pip install cxxheaderparser ``` -------------------------------- ### Run Tests with Pytest Source: https://github.com/robotpy/cxxheaderparser/blob/main/tests/README.md Install the necessary packages and run pytest to execute the test suite. ```bash pytest ``` -------------------------------- ### CLI Dump Tool Usage Source: https://context7.com/robotpy/cxxheaderparser/llms.txt Examples of using the `cxxheaderparser` command-line interface to inspect parsed C++ header files in various formats. ```bash # Pretty-print output (default) python -m cxxheaderparser myheader.h ``` ```bash # JSON output (pipe-friendly) python -m cxxheaderparser --mode=json myheader.h | python -m json.tool ``` ```bash # Dataclass repr (copy-paste into test files) python -m cxxheaderparser --mode=repr myheader.h ``` ```bash # Black-formatted dataclass repr python -m cxxheaderparser --mode=brepr myheader.h ``` ```bash # Show preprocessed output only (requires pcpp or gcc) python -m cxxheaderparser --mode=pponly --pcpp myheader.h ``` ```bash # Use GCC as preprocessor with defines and include paths python -m cxxheaderparser --gcc myheader.h ``` ```bash # Use pcpp as preprocessor python -m cxxheaderparser --pcpp myheader.h ``` ```bash # Generate a depfile (requires --pcpp or --gcc) python -m cxxheaderparser --gcc --depfile build/myheader.d --deptarget build/myobj.o myheader.h ``` ```bash # Read from stdin cat myheader.h | python -m cxxheaderparser - ``` -------------------------------- ### Collecting Function Declarations with CxxParser Source: https://context7.com/robotpy/cxxheaderparser/llms.txt Implement a CxxVisitor to collect only function declarations from C++ code. This example demonstrates how to define a visitor class and use CxxParser to process a string containing function definitions. ```python from cxxheaderparser.parser import CxxParser from cxxheaderparser.options import ParserOptions from cxxheaderparser.types import Function, Variable, EnumDecl, ClassDecl from cxxheaderparser.parserstate import NamespaceBlockState, ClassBlockState, NonClassBlockState class FunctionCollector: """Collects only function declarations, ignoring everything else.""" def __init__(self): self.functions = [] def on_parse_start(self, state): pass def on_pragma(self, state, content): pass def on_include(self, state, filename): pass def on_extern_block_start(self, state): return None def on_extern_block_end(self, state): pass def on_namespace_start(self, state): return None # recurse into all namespaces def on_namespace_end(self, state): pass def on_namespace_alias(self, state, alias): pass def on_concept(self, state, concept): pass def on_forward_decl(self, state, fdecl): pass def on_template_inst(self, state, inst): pass def on_variable(self, state, v): pass def on_typedef(self, state, typedef): pass def on_using_namespace(self, state, namespace): pass def on_using_alias(self, state, using): pass def on_using_declaration(self, state, using): pass def on_enum(self, state, enum): pass def on_class_start(self, state): return False # skip class internals def on_class_field(self, state, f): pass def on_class_friend(self, state, friend): pass def on_class_method(self, state, method): pass def on_class_end(self, state): pass def on_method_impl(self, state, method): pass def on_deduction_guide(self, state, guide): pass def on_function(self, state: NonClassBlockState, fn: Function) -> None: self.functions.append(fn) content = """ int foo(int x, double y); void bar(); namespace inner { bool baz(const char* s); } """ visitor = FunctionCollector() parser = CxxParser("", content, visitor, options=None) parser.parse() for fn in visitor.functions: ret = fn.return_type.format() if fn.return_type else "void" params = ", ".join(p.format() for p in fn.parameters) print(f"{ret} {fn.name.format()}({params})") # int foo(int x, double y) # void bar() # bool inner::baz(const char* s) ``` -------------------------------- ### make_gcc_preprocessor: GCC/G++ preprocessor backend Source: https://context7.com/robotpy/cxxheaderparser/llms.txt Uses GCC/G++ for preprocessing, offering higher accuracy for complex headers but requiring GCC installation. Errors on unresolvable includes. ```python import pathlib from cxxheaderparser.preprocessor import make_gcc_preprocessor from cxxheaderparser.options import ParserOptions from cxxheaderparser.simple import parse_file pp = make_gcc_preprocessor( defines=["NDEBUG", "VERSION 3"], include_paths=["/usr/include", "include/"], retain_all_content=False, gcc_args=["g++"], # or full path, e.g. ["/usr/bin/g++"] print_cmd=True, # prints the g++ command to stderr depfile=pathlib.Path("build/myheader.d"), # optional dependency file deptarget=["build/mylib.o"], ) options = ParserOptions(preprocessor=pp) parsed = parse_file("include/mylib.h", options=options) for fn in parsed.namespace.functions: print(fn.name.format(), "->", fn.return_type.format() if fn.return_type else "void") ``` -------------------------------- ### Test Generator (gentest) Usage Source: https://context7.com/robotpy/cxxheaderparser/llms.txt Examples of using the `cxxheaderparser.gentest` module to automatically generate pytest unit tests from C++ header files. ```bash # Generate a test for a header (prints to stdout) python -m cxxheaderparser.gentest myheader.h my_test_name ``` ```bash # Save to a file python -m cxxheaderparser.gentest myheader.h my_test_name -o tests/test_myheader.py ``` ```bash # Generate a test that expects a parse failure python -m cxxheaderparser.gentest myheader.h fail_case -x ``` ```bash # Generate a test for parse_typename (single type expression in file) python -m cxxheaderparser.gentest type.txt my_type_test --typename ``` ```bash # With pcpp preprocessing python -m cxxheaderparser.gentest myheader.h my_test --pcpp ``` -------------------------------- ### Generated Test Example Source: https://context7.com/robotpy/cxxheaderparser/llms.txt An example of a pytest test function automatically generated by `cxxheaderparser.gentest`. ```python # Auto-generated by: python -m cxxheaderparser.gentest example.h my_example def test_my_example() -> None: content = """ int x; """ data = parse_string(content, cleandoc=True) assert data == ParsedData( namespace=NamespaceScope( variables=[Variable(name=PQName(segments=[NameSpecifier(name="x")]), type=Type(typename=PQName(segments=[FundamentalSpecifier(name="int")])))] ) ) ``` -------------------------------- ### Implement and Use a Custom CxxVisitor Source: https://github.com/robotpy/cxxheaderparser/blob/main/docs/custom.md Define a visitor implementing the CxxVisitor protocol and pass it to CxxParser to collect data during parsing. This approach is useful for advanced customization needs. ```python visitor = MyVisitor() parser = CxxParser(filename, content, visitor) parser.parse() # do something with the data collected by the visitor ``` -------------------------------- ### Implement CxxVisitor for Class Auditing Source: https://context7.com/robotpy/cxxheaderparser/llms.txt Implement the CxxVisitor protocol to audit C++ classes, reporting virtual methods and public fields. Returning False from specific 'on_*_start' methods can skip parsing entire blocks. ```python from cxxheaderparser.visitor import CxxVisitor from cxxheaderparser.types import ClassDecl, Method, Field, EnumDecl from cxxheaderparser.parserstate import ClassBlockState, NamespaceBlockState from cxxheaderparser.parser import CxxParser import typing class ClassAuditVisitor: """Audits classes: reports virtual methods and public fields.""" def __init__(self): self._class_stack = [] self.report = [] def on_parse_start(self, state): pass def on_pragma(self, state, content): pass def on_include(self, state, filename): pass def on_extern_block_start(self, state): return None def on_extern_block_end(self, state): pass def on_namespace_start(self, state): return None def on_namespace_end(self, state): pass def on_namespace_alias(self, state, alias): pass def on_concept(self, state, concept): pass def on_forward_decl(self, state, fdecl): pass def on_template_inst(self, state, inst): pass def on_variable(self, state, v): pass def on_function(self, state, fn): pass def on_method_impl(self, state, method): pass def on_typedef(self, state, typedef): pass def on_using_namespace(self, state, namespace): pass def on_using_alias(self, state, using): pass def on_using_declaration(self, state, using): pass def on_enum(self, state, enum): pass def on_deduction_guide(self, state, guide): pass def on_class_friend(self, state, friend): pass def on_class_start(self, state: ClassBlockState) -> typing.Optional[bool]: name = state.class_decl.typename.segments[-1].name self._class_stack.append(name) return None # recurse into class def on_class_method(self, state: ClassBlockState, method: Method) -> None: cls = self._class_stack[-1] if method.virtual: pure = " (pure)" if method.pure_virtual else "" self.report.append(f"{cls}::{method.name.segments[-1].name} is virtual{pure}") def on_class_field(self, state: ClassBlockState, f: Field) -> None: cls = self._class_stack[-1] if f.access == "public": self.report.append(f"{cls} has public field: {f.type.format()} {f.name}") def on_class_end(self, state: ClassBlockState) -> None: self._class_stack.pop() content = """ class Animal { public: int legs; virtual void speak() = 0; virtual ~Animal(); }; class Dog : public Animal { public: void speak() override; }; """ v = ClassAuditVisitor() CxxParser("", content, v).parse() for line in v.report: print(line) # Animal has public field: int legs # Animal::speak is virtual (pure) # Animal::~Animal is virtual ``` -------------------------------- ### ParserOptions: Default and Void Normalization Source: https://context7.com/robotpy/cxxheaderparser/llms.txt Configures parser behavior using ParserOptions, including default settings and C-style void parameter normalization. ```python from cxxheaderparser.options import ParserOptions from cxxheaderparser.simple import parse_string # Default options (void params normalized, no preprocessor) options = ParserOptions( verbose=False, # set True to print debug output convert_void_to_zero_params=True # treat f(void) as f() ) # C-style void parameter normalization content_c = "void fn(void);" parsed = parse_string(content_c, options=options) fn = parsed.namespace.functions[0] print(len(fn.parameters)) # 0 (void converted to empty list) ``` ```python from cxxheaderparser.options import ParserOptions from cxxheaderparser.simple import parse_string # Disable normalization options_no_convert = ParserOptions(convert_void_to_zero_params=False) content_c = "void fn(void);" parsed2 = parse_string(content_c, options=options_no_convert) fn2 = parsed2.namespace.functions[0] print(len(fn2.parameters)) # 1 (the 'void' parameter is kept) ``` -------------------------------- ### make_msvc_preprocessor: MSVC cl.exe preprocessor backend Source: https://context7.com/robotpy/cxxheaderparser/llms.txt Leverages MSVC's cl.exe for preprocessing, ideal for Windows SDK or MSVC-specific headers. Requires cl.exe to be in the PATH or specified. ```python from cxxheaderparser.preprocessor import make_msvc_preprocessor from cxxheaderparser.options import ParserOptions from cxxheaderparser.simple import parse_file pp = make_msvc_preprocessor( defines=["WIN32", "_WINDOWS", "MYLIB_EXPORTS"], include_paths=["C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.22621.0\\um"], msvc_args=["cl.exe"], # or full path to cl.exe print_cmd=True, ) options = ParserOptions(preprocessor=pp) parsed = parse_file("include\mywinlib.h", options=options) for fn in parsed.namespace.functions: if fn.msvc_convention: print(fn.msvc_convention, fn.name.format()) # e.g. "__stdcall MyFunc" ``` -------------------------------- ### Dump Header Data with cxxheaderparser Source: https://github.com/robotpy/cxxheaderparser/blob/main/docs/tools.md Use the dump tool to output header information to stdout. Specify the desired output format using the --mode flag. ```sh python -m cxxheaderparser myheader.h ``` ```sh python -m cxxheaderparser --mode=json myheader.h ``` ```sh python -m cxxheaderparser --mode=repr myheader.h ``` ```sh python -m cxxheaderparser --mode=brepr myheader.h ``` -------------------------------- ### Type Formatting Methods Source: https://context7.com/robotpy/cxxheaderparser/llms.txt Demonstrates the use of `.format()` and `.format_decl(name)` methods on type-related dataclasses to generate C++ type strings and named declaration strings. ```python from cxxheaderparser.simple import parse_string content = """ int* p; const char* const* ppcc; void (*fn_ptr)(int, double); int arr[10][20]; int& ref; int&& rref; """ parsed = parse_string(content, cleandoc=True) for var in parsed.namespace.variables: t = var.type name = var.name.segments[-1].name print(t.format()) # type string without name print(t.format_decl(name)) # full declaration print() ``` -------------------------------- ### Handle CxxParseError Exceptions Source: https://context7.com/robotpy/cxxheaderparser/llms.txt Demonstrates how to catch and handle `CxxParseError` exceptions raised during parsing. It shows how to access the error message and the offending token if available. ```python import re import pytest from cxxheaderparser.simple import parse_string, parse_typename from cxxheaderparser.errors import CxxParseError # Handling a parse error gracefully bad_content = "int foo( {;" # syntax error try: parsed = parse_string(bad_content) except CxxParseError as e: print(f"Parse failed: {e}") if e.tok: print(f" at token: {e.tok.value!r} (line {e.tok.lineno})") # parse_typename error try: t = parse_typename("int & & bad") # invalid double-ref except CxxParseError as e: print(f"Type parse failed: {e}") # In tests, use pytest.raises with re.escape for exact matching def test_bad_syntax(): err = "Expected )" with pytest.raises(CxxParseError, match=re.escape(err)): parse_string("void fn(int x;") ``` -------------------------------- ### make_pcpp_preprocessor: Pure-Python pcpp preprocessor Source: https://context7.com/robotpy/cxxheaderparser/llms.txt Creates a preprocessor function using pcpp, suitable for environments where GCC/MSVC are unavailable. Missing include files are silently ignored. ```python from cxxheaderparser.preprocessor import make_pcpp_preprocessor from cxxheaderparser.options import ParserOptions from cxxheaderparser.simple import parse_string pp = make_pcpp_preprocessor( defines=["PLATFORM_LINUX", "MY_API=__attribute__((visibility(\"default\")))"], include_paths=["/usr/include"], retain_all_content=False, # strip included file content (default) ) options = ParserOptions(preprocessor=pp) content = """ #ifdef PLATFORM_LINUX MY_API int platform_init(int flags); #else int platform_init(int flags); #endif """ parsed = parse_string(content, options=options) fn = parsed.namespace.functions[0] print(fn.name.segments[-1].name) # "platform_init" print(fn.parameters[0].type.format()) # "int" ``` -------------------------------- ### Generate Unit Test with cxxheaderparser.gentest Source: https://github.com/robotpy/cxxheaderparser/blob/main/docs/tools.md Generate a unit test for cxxheaderparser by providing the C++ header filename and a test name. The output can be copied to test files. ```sh python -m cxxheaderparser.gentest FILENAME.h TESTNAME ``` -------------------------------- ### Generate New Tests Source: https://github.com/robotpy/cxxheaderparser/blob/main/tests/README.md Use the gentest script to generate unit tests by providing a C++ header file and a name. ```python python -m cxxheaderparser.gentest FILENAME.h some_name ``` -------------------------------- ### Parse Type Name Source: https://context7.com/robotpy/cxxheaderparser/llms.txt Demonstrates parsing a C++ type name and accessing its segments. ```python from cxxheaderparser.types import Type, PQName from cxxheaderparser.simple import parse_typename t2 = parse_typename("unsigned long long") assert isinstance(t2, Type) print(t2.typename.segments[0].name) # "unsigned long long" ``` -------------------------------- ### Parse C++ File with Simple API Source: https://context7.com/robotpy/cxxheaderparser/llms.txt Reads a C++ header file from disk and returns a ParsedData structure. Supports custom preprocessor options for macro expansion. ```python from cxxheaderparser.simple import parse_file from cxxheaderparser.options import ParserOptions from cxxheaderparser.preprocessor import make_pcpp_preprocessor # Basic usage parsed = parse_file("include/mylib.h") # With preprocessor to expand macros options = ParserOptions( preprocessor=make_pcpp_preprocessor( defines=["MYLIB_API=", "VERSION 2"], include_paths=["/usr/include", "include/"] ) ) parsed = parse_file("include/mylib.h", options=options) # Iterate over all top-level variables for var in parsed.namespace.variables: print(var.type.format(), var.name.format(), "=", var.value.format() if var.value else "") # Check included files and pragmas for inc in parsed.includes: print("#include", inc.filename) # e.g. "" for pragma in parsed.pragmas: print("#pragma", pragma.content.format()) ``` -------------------------------- ### parse_file Source: https://context7.com/robotpy/cxxheaderparser/llms.txt Reads a C++ header file from a specified path and returns a ParsedData object, mirroring the functionality of `parse_string`. It can also read from stdin. ```APIDOC ## parse_file — Parse a C++ header from a file path ### Description Reads a C++ header file from disk (or stdin when `filename="-"`) and returns the same `ParsedData` structure as `parse_string`. Defaults to UTF-8-sig encoding. ### Usage ```python from cxxheaderparser.simple import parse_file from cxxheaderparser.options import ParserOptions from cxxheaderparser.preprocessor import make_pcpp_preprocessor # Basic usage parsed = parse_file("include/mylib.h") # With preprocessor to expand macros options = ParserOptions( preprocessor=make_pcpp_preprocessor( defines=["MYLIB_API=", "VERSION 2"], include_paths=["/usr/include", "include/"] ) ) parsed = parse_file("include/mylib.h", options=options) # Iterate over all top-level variables for var in parsed.namespace.variables: print(var.type.format(), var.name.format(), "=", var.value.format() if var.value else "") # Check included files and pragmas for inc in parsed.includes: print("#include", inc.filename) # e.g. "" for pragma in parsed.pragmas: print("#pragma", pragma.content.format()) ``` ``` -------------------------------- ### parse_string Source: https://context7.com/robotpy/cxxheaderparser/llms.txt Parses C++ header content provided as a Python string and returns a structured ParsedData object. This is useful for analyzing in-memory C++ code snippets. ```APIDOC ## parse_string — Parse C++ source from a string ### Description Parses a C++ header supplied as a Python string and returns a `ParsedData` dataclass containing the full structure of the header organized into namespaces, classes, functions, variables, enums, and more. ### Usage ```python from cxxheaderparser.simple import parse_string from cxxheaderparser.options import ParserOptions content = """ namespace mylib { /// Computes the sum of two integers. int add(int a, int b); template class Container { public: Container(T value); T get() const; void set(T value); private: T _value; }; enum class Color : uint8_t { Red = 0, Green = 1, Blue = 2, }; } // namespace mylib """ parsed = parse_string(content, cleandoc=True) # Access the 'mylib' namespace ns = parsed.namespace.namespaces["mylib"] # Inspect functions for fn in ns.functions: print(fn.name.segments[-1].name) # "add" print(fn.doxygen) # "/// Computes the sum..." for param in fn.parameters: print(param.type.format(), param.name) # "int a", "int b" # Inspect classes for cls in ns.classes: print(cls.class_decl.typename.segments[-1].name) # "Container" for method in cls.methods: print(method.name.segments[-1].name, method.access) for field in cls.fields: print(field.type.format(), field.name, field.access) # Inspect enums for enum in ns.enums: print(enum.typename.segments[-1].name) # "Color" for val in enum.values: print(val.name, val.value.format() if val.value else "auto") # Color Red 0 Green 1 Blue 2 ``` ``` -------------------------------- ### Parse C++ String with Simple API Source: https://context7.com/robotpy/cxxheaderparser/llms.txt Parses a C++ header from a string and returns a ParsedData dataclass. Useful for inspecting namespaces, classes, functions, and enums. ```python from cxxheaderparser.simple import parse_string from cxxheaderparser.options import ParserOptions content = """ namespace mylib { /// Computes the sum of two integers. int add(int a, int b); template class Container { public: Container(T value); T get() const; void set(T value); private: T _value; }; enum class Color : uint8_t { Red = 0, Green = 1, Blue = 2, }; } // namespace mylib """ parsed = parse_string(content, cleandoc=True) # Access the 'mylib' namespace ns = parsed.namespace.namespaces["mylib"] # Inspect functions for fn in ns.functions: print(fn.name.segments[-1].name) # "add" print(fn.doxygen) # "/// Computes the sum..." for param in fn.parameters: print(param.type.format(), param.name) # "int a", "int b" # Inspect classes for cls in ns.classes: print(cls.class_decl.typename.segments[-1].name) # "Container" for method in cls.methods: print(method.name.segments[-1].name, method.access) for field in cls.fields: print(field.type.format(), field.name, field.access) # Inspect enums for enum in ns.enums: print(enum.typename.segments[-1].name) # "Color" for val in enum.values: print(val.name, val.value.format() if val.value else "auto") # Color Red 0 Green 1 Blue 2 ``` -------------------------------- ### Parse C++ Code with parse_string Source: https://context7.com/robotpy/cxxheaderparser/llms.txt Use the `parse_string` function to parse C++ code content and access the results via ParsedData, NamespaceScope, and ClassScope objects. The `cleandoc` argument can be used to clean documentation strings. ```python from cxxheaderparser.simple import parse_string, ParsedData, NamespaceScope, ClassScope content = """ #pragma once #include namespace utils { namespace detail { using Index = int; } template struct Result { bool ok; T value; using value_type = T; }; using StringResult = Result; } """ parsed: ParsedData = parse_string(content, cleandoc=True) # Top-level preprocessor directives print(parsed.pragmas[0].content.format()) # "once" print(parsed.includes[0].filename) # "" # Navigate namespaces utils_ns: NamespaceScope = parsed.namespace.namespaces["utils"] detail_ns: NamespaceScope = utils_ns.namespaces["detail"] print(detail_ns.using_alias[0].alias) # "Index" print(detail_ns.using_alias[0].type.format()) # "int" # Access a class/struct result_cls: ClassScope = utils_ns.classes[0] print(result_cls.class_decl.typename.segments[-1].name) # "Result" print(result_cls.class_decl.template.params[0].typekey) # "typename" for field in result_cls.fields: print(field.access, field.type.format(), field.name) # public bool ok # public T value for ua in result_cls.using_alias: print(ua.alias, "=", ua.type.format()) # value_type = T # using alias in namespace print(utils_ns.using_alias[0].alias) # "StringResult" ``` -------------------------------- ### Parse C++ Type Name Source: https://context7.com/robotpy/cxxheaderparser/llms.txt Parses a single C++ type name into a DecoratedType object. Useful for resolving type strings independently. ```python from cxxheaderparser.simple import parse_typename from cxxheaderparser.types import Pointer, Reference, MoveReference, Type, Array # Fundamental type t = parse_typename("int") print(t.format()) # "int" # Const pointer to char t = parse_typename("const char *") print(t.format()) # "const char*" # Reference to const std::string t = parse_typename("const std::string &") print(t.format()) # "const std::string&" # Array of int t = parse_typename("int[10]") print(t.format()) # "int[10]" # Function pointer t = parse_typename("void (*)(int, double)") print(t.format()) # "void (int, double)" # Rvalue reference t = parse_typename("std::vector &&") print(t.format()) # "std::vector&&" ``` -------------------------------- ### parse_typename Source: https://context7.com/robotpy/cxxheaderparser/llms.txt Parses a standalone C++ type expression into a `DecoratedType` object, useful for resolving type strings independently of full declarations. ```APIDOC ## parse_typename — Parse a standalone C++ type expression ### Description Parses a single C++ type name (not a full declaration) and returns a `DecoratedType` object. Useful for resolving type strings encountered elsewhere. ### Usage ```python from cxxheaderparser.simple import parse_typename from cxxheaderparser.types import Pointer, Reference, MoveReference, Type, Array # Fundamental type t = parse_typename("int") print(t.format()) # "int" # Const pointer to char t = parse_typename("const char *") print(t.format()) # "const char*" # Reference to const std::string t = parse_typename("const std::string &") print(t.format()) # "const std::string&" # Array of int t = parse_typename("int[10]") print(t.format()) # "int[10]" # Function pointer t = parse_typename("void (*)(int, double)") print(t.format()) # "void (int, double)" # Rvalue reference t = parse_typename("std::vector &&") print(t.format()) # "std::vector&&" ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.