Parser Backends¶
autopxd2 ships two parser backends: libclang (the default) and tree-sitter.
$ autopxd --list-backends
Available backends:
libclang Full C/C++ support via LLVM [available] (default)
tree-sitter Fast C/C++ parsing without system LLVM dependencies [available]
Default: libclang
Choosing a Backend¶
| libclang | tree-sitter | |
|---|---|---|
| Install | needs the system libclang shared library |
pip install "autopxd2[treesitter]", no system LLVM |
Follows #include directives |
✅ | ❌ (parses the given file only) |
#define macro extraction |
✅ | ❌ |
| System include path detection | ✅ | ❌ |
| C++ classes, templates, namespaces | ✅ | ✅ |
--std / --clang-arg |
✅ | ❌ (rejected with an error) |
Use libclang unless you cannot install LLVM. Use tree-sitter for self-contained
headers in environments (such as minimal CI or Docker containers) where a system libclang is unavailable.
libclang¶
Uses LLVM's clang library for parsing. Provides the same parser used by production compilers.
Features:
- Full C++ support (classes, templates, namespaces)
- Extracts macros as constants (integers, floats, strings, expressions)
- Automatic system include path detection
- Follows and recursively expands
#includedirectives across translation units - Handles comments and preprocessor directives directly
- Better error messages
- Handles complex and umbrella headers reliably
Limitations:
- Requires libclang shared library to be available on your system (use
python -m headerkit.install_libclangor install LLVM manually) - Function-like macros are not extracted
Usage:
tree-sitter¶
Uses tree-sitter grammars for C and C++. It needs no system LLVM, so it installs and runs anywhere Python does using pre-built PyPI wheels.
Install:
Usage:
autopxd --backend tree-sitter myheader.h
# C++ works too
autopxd --backend tree-sitter --cpp myclass.hpp
Limitations:
The tree-sitter backend is substantially more limited than libclang:
- No
#includerecursion: It parses only the file given to it. Given#include "inner.h"or#include <header.h>, declarations from the included headers do not appear in the output; only the parsed file's own declarations do. If the header relies on types defined in included files, those type definitions will not be present. - No
#definemacro extraction: Constants and macro functions defined via#defineare not extracted into the.pxd. - No system include paths: It does not query or search compiler system include directories.
- Rejects compiler driver options: Options that configure the compiler frontend (
--stdand--clang-arg) are rejected with an explicit error:
$ autopxd --backend tree-sitter --std c11 myheader.h
Error: --std is only supported by the libclang backend, but the resolved backend is 'tree-sitter'.
Use --backend libclang, or drop the option.
When to use tree-sitter:
- Single, self-contained C or C++ header files.
- Headless CI pipelines, Docker containers, or minimal environments (e.g. Alpine/musllinux) where installing LLVM/Clang is impractical.
- When you do not need macro constants or included header declarations in the generated .pxd.
System Include Paths¶
The libclang backend automatically detects system include directories by querying the system clang compiler. This means headers like <stddef.h> and <stdint.h> work without requiring manual -I flags.
To disable automatic include detection:
You can still add additional include directories:
Macro Extraction¶
The libclang backend extracts #define macros as Cython constant declarations. The type is automatically detected from the macro value.
Integer Macros¶
Generates int declarations:
Supported formats: decimal, hex (0x), octal (0), binary (0b), with optional type suffixes (U, L, UL, LL, ULL).
Floating-Point Macros¶
Generates double declarations:
String Macros¶
Generates const char* declarations:
Expression Macros¶
Expression macros that consist of numeric literals, operators, and other macro references are detected and declared with appropriate types:
Unsupported Macros (silently ignored)¶
- Function-like macros:
#define MAX(a, b) ((a) > (b) ? (a) : (b)) - Empty macros:
#define EMPTY - String concatenation:
#define CONCAT "hello" "world"
C++ Template Support¶
The backends support C++ templates, including primary templates and full specializations.
Primary Templates¶
C++ class templates with type parameters are translated to Cython's template syntax:
Generates:
Multiple type parameters are supported:
template<typename K, typename V>
class Map {
public:
V lookup(K key);
void insert(K key, V value);
};
Generates:
Template Specializations¶
Full template specializations are emitted with mangled Python-safe names and the original C++ name as a string literal:
Generates:
The mangling scheme converts special characters to valid Python identifiers:
- < and > are removed, contents become underscore-separated
- * becomes _ptr
- & becomes _ref
- :: becomes _
Examples:
- Container<int> -> Container_int
- Map<int, double> -> Map_int_double
- Foo<int*> -> Foo_int_ptr
Using Docker for libclang¶
If you don't want to install libclang locally, use the Docker image:
See Docker Usage for details.