Show HN: Mirror_bridge – C++ Reflection powered Python binding generation

2025/12/04 15:12

Show HN: Mirror_bridge – C++ Reflection powered Python binding generation

RSS: https://news.ycombinator.com/rss

要約

本文

Mirror Bridge Modern C++ meets Multiple Languages: Automatic bindings using C++26 reflection - zero boilerplate, pure compile-time magic.

⚠️ EXPERIMENTAL: This project requires C++26 reflection (P2996), which is not yet standardized. It only works with Bloomberg's clang-p2996 fork. Not recommended for production use until P2996 lands in standard C++26.

One C++ Class, Three Languages // Write your C++ code once struct Calculator { double value = 0.0; double add(double x) { return value += x; } double subtract(double x) { return value -= x; } }; Python: import cpp_calc calc = cpp_calc.Calculator() calc.add(10) calc.subtract(3) print(calc.value) # 7.0 JavaScript (Node.js): const calc = new addon.Calculator(); calc.add(10); calc.subtract(3); console.log(calc.x); // 7.0 Lua: local calc = cpp_calc.Calculator() calc:add(10) calc:subtract(3) print(calc.value) -- 7.0 No manual binding code. No wrapper macros. Just pure C++26 reflection. 🎉 Supported Languages

Language Status API Example

Python ✅ Stable Python C API import my_module

JavaScript ✅ Stable Node.js N-API const mod = require('my_module')

Lua ✅ Stable Lua C API local mod = require("my_module")

What is Mirror Bridge? Mirror Bridge is a header-only library that uses C++26 reflection (P2996) to automatically introspect your C++ classes at compile-time and generate bindings for Python, JavaScript, and Lua. It discovers:

✅ Data members - automatic getters/setters with type safety ✅ Methods (any number of parameters) - variadic parameter support ✅ Constructors - including parameterized constructors ✅ Method overloading - automatic name mangling for overloads ✅ Smart pointers - std::unique_ptr, std::shared_ptr with automatic conversion ✅ Nested classes - recursive handling, cross-file dependencies ✅ Containers - std::vector, std::array with bidirectional conversion ✅ Exception handling - C++ exceptions → Python exceptions ✅ Enums - automatic conversion to/from Python int ✅ Object representation - automatic repr implementation ✅ Inheritance - reflection automatically discovers inherited members

Zero overhead: All binding code is generated at compile-time through template metaprogramming and reflection - no runtime costs. Quick Start

1. Get the environment

./start_dev_container.sh

Choose option 1 to pull pre-built image (~2 min)

2. Inside container - verify it works

cd /workspace && ./tests/run_all_tests.sh

3. Try an example

cd examples/option2 ../../mirror_bridge_auto src/ --module math_module python3 test_option2.py That's it! See QUICKSTART.md for a detailed walkthrough. Two Approaches to Auto-Generation Mirror Bridge offers two workflows optimized for different use cases: Option 1: Auto-Discovery (Minimal Friction) Just point at a directory - bindings are auto-generated for all classes. Python: mirror_bridge_auto src/ --module my_module Lua: mirror_bridge_auto_lua src/ --module my_module JavaScript (Node.js): mirror_bridge_auto_js src/ --module my_module

✅ Zero configuration - discovers all classes automatically ✅ Perfect for prototyping and small projects ✅ Opt-out via comments - mark classes to skip ✅ Works for all three languages - Python, Lua, JavaScript

Example: // src/calculator.hpp struct Calculator { double value; double add(double x); };

// src/vector3.hpp struct Vector3 { double x, y, z; double length(); };

One command binds BOTH classes

mirror_bridge_auto src/ --module mylib import mylib calc = mylib.Calculator() vec = mylib.Vector3() See examples/option2/ for full example. Option 2: Config File (Production) Declarative config for explicit control over what gets bound. Create my_module.mirror: module: my_module

include_dirs: src/, include/

Calculator: calculator.hpp Vector3: vector3.hpp

mirror_bridge_generate my_module.mirror

✅ Explicit control - only bind what you specify ✅ Version control friendly - declarative config ✅ Class renaming - Foo::Bar: foo.hpp as Bar

See examples/option3/ for full example. Full comparison: examples/README.md Single-Header Distribution For easier integration, Mirror Bridge provides single-header amalgamated versions for each language. Just copy one file to your project! Generate single-headers:

This creates:

single_header/mirror_bridge_python.hpp (~1771 lines, 65KB) single_header/mirror_bridge_lua.hpp (~859 lines, 32KB) single_header/mirror_bridge_javascript.hpp (~875 lines, 33KB)

Usage: // Instead of: #include "python/mirror_bridge_python.hpp" // Just: #include "mirror_bridge_python.hpp" // Single self-contained header!

MIRROR_BRIDGE_MODULE(my_module, mirror_bridge::bind_class(m, "MyClass"); ) See SINGLE_HEADER_GUIDE.md for complete documentation. What Gets Auto-Generated? Data Members struct Point { double x, y; }; p = my_module.Point() p.x = 3.0 # Automatic getter/setter p.y = 4.0 Methods (Variadic Parameters) struct MathOps { double add3(double a, double b, double c) { return a + b + c; } double sum5(double a, double b, double c, double d, double e) { return a + b + c + d + e; } void reset() { value = 0; } // Zero parameters work too }; ops = my_module.MathOps() ops.add3(1.0, 2.0, 3.0) # 3 parameters ✓ ops.sum5(1, 2, 3, 4, 5) # 5 parameters ✓ ops.reset() # 0 parameters ✓

ANY number of parameters supported through variadic templates

Constructors with Parameters struct Rectangle { Rectangle() : width(0), height(0) {} Rectangle(double w, double h) : width(w), height(h) {} Rectangle(double w, double h, std::string name) : width(w), height(h), name(name) {}

double width, height;
std::string name;

}; r1 = my_module.Rectangle() # Default constructor r2 = my_module.Rectangle(10.0, 5.0) # 2-parameter constructor r3 = my_module.Rectangle(10, 5, "box") # 3-parameter constructor

Automatic constructor discovery and parameter matching

Method Overloading struct Printer { void print(int value) { /* ... / } void print(double value) { / ... / } void print(std::string value) { / ... */ } }; p = my_module.Printer() p.print_int(42) # int overload p.print_double(3.14) # double overload p.print_std__string("hello") # string overload

Automatic name mangling distinguishes overloads

Smart Pointers struct Data { std::string name; int value; };

struct ResourceManager { std::unique_ptr unique_data; std::shared_ptr shared_data;

std::unique_ptr<Data> create_unique(std::string n, int v);

}; rm = my_module.ResourceManager()

Smart pointers convert to/from Python dicts

result = rm.create_unique("test", 42) print(result) # {'name': 'test', 'value': 42}

Set from dict - creates managed pointer automatically

rm.unique_data = {'name': 'data', 'value': 123}

None handling for null pointers

rm.unique_data = None # Sets to nullptr Nested Classes struct Address { std::string city; };

struct Person { std::string name; Address addr; // Nested! }; p = my_module.Person() p.addr = {'city': 'Boston'} # Dict conversion Containers struct Data { std::vector values; std::array<int, 3> coords; }; d.values = [1.0, 2.0, 3.0] # List → vector d.coords = [1, 2, 3] # List → array Exception Handling double divide(double x) { if (x == 0) throw std::runtime_error("Division by zero"); return value / x; } try: calc.divide(0) except RuntimeError as e: print(e) # "Division by zero" Project Structure mirror_bridge/ ├── mirror_bridge.hpp # Single-header library (core reflection logic) ├── mirror_bridge_pch.hpp # Precompiled header wrapper (optional) ├── mirror_bridge_auto # Auto-discovery script ├── mirror_bridge_generate # Config file script ├── mirror_bridge_build # Direct compilation script ├── mirror_bridge_build_pch # PCH builder script (optional) ├── start_dev_container.sh # Docker setup (persistent container) ├── examples/ │ ├── README.md # Detailed usage guide │ ├── option2/ # Auto-discovery example │ └── option3/ # Config file example └── tests/ ├── run_all_tests.sh # Automated test suite ├── test_pch.sh # PCH functionality test └── e2e/ # End-to-end tests ├── basic/ # Point2D, Vector3 ├── containers/ # std::vector, std::array ├── nesting/ # Nested classes, cross-file └── methods/ # Method binding (Calculator)

How It Works Mirror Bridge leverages C++26 reflection at compile-time:

Discovery: Uses std::meta::nonstatic_data_members_of(^^T) to find all class members Method Introspection: Uses std::meta::members_of + std::meta::is_function to find methods Type Extraction: Uses std::meta::type_of and std::meta::identifier_of for names Code Generation: Generates Python C API bindings via template metaprogramming Compilation: Compiles to .so module with reflection-enabled clang

All binding logic is resolved at compile-time - zero runtime overhead. See CONTRIBUTING.md for technical details. Requirements

Compiler: Bloomberg clang-p2996 (P2996 reflection support)

Provided via Docker: ./start_dev_container.sh Or build from: https://github.com/bloomberg/clang-p2996

Python: 3.7+ Platform: Linux (or macOS with Docker)

Testing

Inside Docker container:

Run all automated tests

./tests/run_all_tests.sh

Output:

✓ Built: 12 bindings

✓ Passed: 12 tests

✓ ALL TESTS PASSED!

Test coverage:

- Basic data members (Point2D, Vector3)

- Containers (std::vector, std::array)

- Nested classes (2-level, 3-level, cross-file)

- Methods (Calculator with various signatures)

- Variadic parameters (3, 4, 5, 6 parameter methods)

- Constructors with parameters (0, 2, 3 parameters)

- Method overloading (int/double/string overloads)

- Smart pointers (unique_ptr, shared_ptr conversion)

Advanced feature tests (tests/e2e/advanced/):

Variadic: Methods with 3-6 parameters, weighted sums, format functions Constructors: Default, 2-param, 3-param constructor matching Overloading: Type-based name mangling for overloaded methods Smart Pointers: Bidirectional dict conversion, nullptr handling, return values

Documentation

CONTRIBUTING.md - Development guide: setup, testing, CLI tools, architecture examples/README.md - Usage examples and workflow comparisons API Reference - Inline documentation in mirror_bridge.hpp

Current Limitations

Passing bound class instances as parameters (requires reference/pointer handling) Template classes (must be explicitly instantiated before binding) Const method overloads (treated as same method currently) Advanced smart pointers (weak_ptr, custom deleters)

Roadmap Recently Completed:

✅ Variadic parameter support (any number of parameters) ✅ Constructor parameter binding ✅ Method overloading via name mangling ✅ Smart pointer support (unique_ptr, shared_ptr)

Next:

Reference parameters and bound class passing Const method overload distinction Template class binding automation Additional backends (Rust, Lua) Python stub generation (.pyi files)

Performance Mirror Bridge delivers significant performance improvements over pybind11: Compile-Time: 2-3x faster

Simple project (1 class): 816ms vs 1,938ms pybind11 (2.4x faster) Medium project (10 classes): 1,543ms vs 3,637ms pybind11 (2.4x faster) Why: Reflection eliminates template metaprogramming overhead

Runtime: 3-5x faster

Function calls: 35ns vs 127ns pybind11 (3.6x faster) Object construction: 47ns vs 256ns pybind11 (5.4x faster) Why: Direct Python C API calls, no template dispatch

Developer Experience: Zero boilerplate

Auto-discovery: mirror_bridge_auto src/ --module name No binding code required vs 18-103 lines for pybind11 Instant: Add members/methods → automatically bound

Methodology: 5 runs per test, median ± stddev reported, identical optimization flags (-O3 -DNDEBUG) Precompiled Headers (PCH): 3-6x faster compilation For even faster builds, use precompiled headers to cache the Mirror Bridge infrastructure:

One-time: Build PCH (takes ~600ms, reuse forever)

./mirror_bridge_build_pch -o build -t release

Every build: Use PCH for 3-6x faster compilation

mirror_bridge_auto src/ --module my_module --use-pch build/mirror_bridge_pch.hpp.gch Performance with PCH:

Simple project: 567ms → 194ms (66% faster, 2.9x speedup) Medium project: 1580ms → 252ms (84% faster, 6.3x speedup) One-time cost: ~600ms to build PCH (amortized across all builds)

Key benefits:

✅ Shared across projects - build PCH once, use everywhere ✅ Debug/Release PCH - separate PCH for different build configurations ✅ Zero code changes - just add --use-pch flag ✅ Automatic detection - mirror_bridge_auto finds PCH automatically

Complete guide: See PCH_GUIDE.md and WORKFLOW_GUIDE.md Test suite: Run ./tests/test_pch.sh to verify PCH infrastructure Benchmarks Run comprehensive tests yourself:

See benchmarks/FINAL_RESULTS.md for complete results and analysis. Contributing This is an experimental project exploring C++26 reflection. Contributions welcome! Areas needing work:

Extended parameter support for methods Template class handling Additional backends (Rust, Lua)

License Apache License 2.0 - See LICENSE for details. Acknowledgments

Bloomberg's clang-p2996 - P2996 reflection implementation P2996 Reflection Proposal simdjson - Concept-based design inspiration

Status: Experimental - C++26 reflection is not yet supported on all C++ compilers. This project uses Bloomberg's clang-p2996 implementation. Yes, method binding works! See calculator tests for full examples.

同じ日のほかのニュース

一覧に戻る →

2025/12/04 3:40

Ghostty is now non-profit

Ghostty は501(c)(3)非営利団体 Hack Club の財務スポンサーシップを受け、税優遇とコンプライアンスを確保しつつ無料・オープンソースで提供されます。 重要ポイント 1. **持続可能性**:個人依存から脱却し、寄付で運営を安定化。 2. **信頼性**:非営利体制により資金の乱用や商業転売が防止。 3. **公共利益**:ターミナル技術を公益優先で発展させ、広範な採用促進。

2025/12/03 5:33

Valve reveals it’s the architect behind a push to bring Windows games to Arm

SteamがArmチップ向けPCゲームの移植を支援し、Steam Frameは実質的にAndroidデバイスやノートPCでSteamを遊べるトロイの木馬。FexとProtonがx86コードをARMへJIT変換し、開発者は移植作業を減らせる。重要ポイント 1. ValveはArm向けオープンソース技術に資金提供している。 2. Fex+ProtonでWindowsゲームをスマホやノートPC上で実行可能。 3. Steam Frameは「VRヘッドセット」ではなく、ArmデバイスでSteam体験を拡張するためのハードウェア。

2025/12/04 2:44

Reverse engineering a $1B Legal AI tool exposed 100k+ confidential files

**要約(300字以内)** FilevineのAI法務プラットフォームで、サブドメイン `margolis.filevine.com` にアクセスすると、Box API管理者トークンが返る脆弱性を発見。1) **発見と報告**:2025年10月27日から責任ある報告を行い、Filevineは迅速に修正。2) **技術的詳細**:エンドポイント `/prod/recommend` に `{"projectName":"Very sensitive Project"}` を送るだけで、全Boxファイルシステムへの完全アクセス権が得られた。3) **リスクと教訓**:機密文書やHIPAA保護資料を数百万件抽出可能となり、法律事務所・クライアントに深刻被害。AI法務テック企業はデータ保護体制を徹底すべきである。