Skip to main content

辻斬り Generic C++ Bindings Generator

Project description

Backdrop

Tests Coverage Documentation PyPI version Python License: MIT

tsujikiri — 辻斬り

Cut through C++ bindings

tsujikiri parses C++ headers via libclang and generates binding code through a template-driven pipeline. Define what to expose, plug in a target format, and get ready-to-compile bindings.

Built-in support for LuaBridge3 (Lua bindings), LuaLS (Lua Language Server annotations), pybind11 (Python bindings), and Python type stubs (.pyi). Custom formats are first-class.


How It Works

C++ Header (.hpp)
    │
    ▼  libclang
Intermediate Representation (IR)
    │
    ├─▶  FilterEngine        suppress classes / methods / fields by pattern
    │
    ├─▶  Transform Pipeline  rename, inject, remap types
    │
    ▼  Jinja2 templates
Target Binding Code

Each phase is independently configurable per input file and per output format.


Documentation

Full documentation is available at tsujikiri.readthedocs.io.


Installation

Using pip:

pip install tsujikiri

Using uv:

uv pip install tsujikiri

Requirements: Python ≥ 3.12


Quick Start

1. Write an input config

# myproject.input.yml
source:
  path: myproject.hpp
  parse_args: ["-std=c++17"]
  include_paths: ["/usr/local/include"]

filters:
  namespaces: ["myproject"]
  classes:
    whitelist: ["Vec3", "Matrix4", "Camera"]
  constructors:
    include: true

generation:
  includes: ["<myproject.hpp>"]

2. Generate bindings

# Print to stdout
tsujikiri -i myproject.input.yml --target luabridge3 -

# Write to file
tsujikiri -i myproject.input.yml --target luabridge3 bindings.cpp

# Generate multiple outputs in one pass
tsujikiri -i myproject.input.yml \
  --target luabridge3 bindings.cpp \
  --target pybind11 py_bindings.cpp \
  --target pyi mymodule.pyi

# Dry-run: parse and filter, print summary
tsujikiri -i myproject.input.yml --target luabridge3 - --dry-run

# List available formats
tsujikiri --list-formats

3. Example output (LuaBridge3)

Given a header with a Vec3 class, tsujikiri emits:

#include <myproject.hpp>
#include <LuaBridge/LuaBridge.h>

void register_myproject(lua_State* L)
{
    luabridge::getGlobalNamespace(L)
        .beginClass<myproject::Vec3>("Vec3")
            .addConstructor<void(*)(float, float, float)>()
            .addFunction("length", &myproject::Vec3::length)
            .addFunction("dot", &myproject::Vec3::dot)
            .addProperty("x", &myproject::Vec3::x)
            .addProperty("y", &myproject::Vec3::y)
            .addProperty("z", &myproject::Vec3::z)
        .endClass();
}

Built-in Formats

luabridge3

Generates C++ registration code for LuaBridge3.

tsujikiri -i project.input.yml --target luabridge3 bindings/lua_bindings.cpp

Handles: classes, constructors, instance/static methods, overloaded methods, properties, enums, free functions, inheritance.

luals

Generates Lua Language Server annotation stubs.

tsujikiri -i project.input.yml --target luals types/myproject.lua

Emits ---@class, ---@field, ---@param, ---@return annotations with C++→Lua type mappings.

pybind11

Generates C++ registration code for pybind11.

tsujikiri -i project.input.yml --target pybind11 src/py_bindings.cpp

Handles: classes with multiple inheritance, constructors, instance/static methods, overloaded methods (via py::overload_cast), read-write/read-only properties, enums (via py::enum_), free functions, doc strings.

pyi

Generates Python type stub files (.pyi) for use alongside pybind11 bindings.

tsujikiri -i project.input.yml --target pyi mymodule.pyi

Emits Python-typed stubs with @overload, @staticmethod, class inheritance, enum stubs as class Foo(int), and C++→Python type mappings.


Custom Formats

Create a myformat.output.yml alongside your templates:

format_name: "myformat"
format_version: "1.0"
description: "My custom binding format"

type_mappings:
  "std::string": "String"
  "int32_t": "int"

unsupported_types:
  - "CFStringRef"

templates:
  prologue: |
    // Generated by tsujikiri
    package {{ module_name }};
  class_begin: "register_class<{{ qualified_class_name }}>(\"{{ class_name }}\""
  # ... define all template keys

Point tsujikiri at your format directory:

tsujikiri -i project.input.yml --target myformat out/bindings.cpp -F ./my_formats/

CLI Reference

tsujikiri [OPTIONS]

Options:
  -i, --input FILE            Input config YAML (required)
  -t, --target FORMAT FILE    Output target: FORMAT is a built-in name or path to
                              .output.yml; FILE is the output path ('-' for stdout).
                              Repeatable for multiple simultaneous outputs.
  -c, --classname CLASS       Generate bindings for a single class only
  -F, --formats-dir DIR       Extra directory to search for .output.yml files (repeatable)
      --list-formats          Print available formats and exit
      --dry-run               Parse and filter only; print IR summary without generating
  -M, --manifest-file FILE    Write API manifest JSON to FILE; compare if FILE exists
      --check-compat          Exit 1 if manifest shows breaking API changes
      --embed-version         Embed the API version hash in the generated code
      --trace-transforms      Print transform stages and their targets to stderr
      --dump-ir [FILE]        Dump the post-transform IR as JSON (default: stdout)
      --validate-config       Validate input config (regex patterns, stage names) and exit
  -h, --help                  Show this message and exit

Development

# Install task runner and sync dependencies
pip install just uv
just sync

# Run tests
just test

# Run tests with coverage
just coverage

# Build wheel
just build

The test suite covers parsing, filtering, transforms, generation, CLI integration, and end-to-end compilation with LuaBridge3.


Coverage

Coverage tree


License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tsujikiri-0.5.0.tar.gz (45.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tsujikiri-0.5.0-py3-none-any.whl (49.3 kB view details)

Uploaded Python 3

File details

Details for the file tsujikiri-0.5.0.tar.gz.

File metadata

  • Download URL: tsujikiri-0.5.0.tar.gz
  • Upload date:
  • Size: 45.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for tsujikiri-0.5.0.tar.gz
Algorithm Hash digest
SHA256 190680e841336d638f5ffe99a96538aa9994a656eb2629a5e2440d2a1ee6ca43
MD5 eeb470529e3fe6db959b7f051b556105
BLAKE2b-256 bba97df7c431d8fffc2012c4f81adcc63cb99af85fd5120eb7ff7b12bed16875

See more details on using hashes here.

Provenance

The following attestation bundles were made for tsujikiri-0.5.0.tar.gz:

Publisher: release.yml on kunitoki/tsujikiri

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tsujikiri-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: tsujikiri-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 49.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for tsujikiri-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9c0aa5b6a2297af47c78ede21aa936b8f332b0377b23e3d0b151d9b524f12908
MD5 a0e9b339651138e29eb9c664cbf11cda
BLAKE2b-256 f896eea3e7cb748c9bac2fb02b79659e3069e9370fd42f74a001f1f43a971f83

See more details on using hashes here.

Provenance

The following attestation bundles were made for tsujikiri-0.5.0-py3-none-any.whl:

Publisher: release.yml on kunitoki/tsujikiri

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page