Guide¶
This guide walks through welder from the ground up: installing the toolchain, the annotation vocabulary, and each binding feature with runnable examples.
- Getting started — toolchain, build, your first module.
- Annotation vocabulary —
weld,policy,mark, and how resolution works. - Binding a type — fields, constructors, methods, operators.
- Binding templates — annotate the template, bind instantiations.
- Enums — scoped/unscoped enums and per-enumerator marks.
- Inheritance — welded bases vs. flattened mixins.
- Namespaces & modules — bind a whole namespace or module in one line.
- Return policies & lifetimes — who owns a returned object, and what keeps it alive.
- Docstrings —
doc/returns/tparamflowing to__doc__and the C++ docs. - Stubs — the generated
.pyiand LuaCATS files your editors and type checkers read. - Naming conventions — pluggable name styles (PEP 8, snake_case, …) and
weld_as. - The bindability gate — why an unrepresentable type is a hard error.
- Trust & type casters — escape hatches for types welder can't see.
- Generating C++ docs — the Doxygen INPUT_FILTER that reads the same annotations.
- Extending welder — write your own rod, doc style, resolution, or entry point.
- Troubleshooting & FAQ — the common errors and their fixes.
Read it in any language
Every feature here is backend-agnostic — the same annotated C++ binds to Python and Lua alike. Examples are shown per language in tabs; pick your tab and the whole guide follows it. When you're ready to choose or combine rods, the Languages section covers each one and how to ship several from one build.
The mental model¶
welder splits into a language-agnostic core and pluggable rods (a rod is a welding rod — the backend that lays a framework's bindings down):
- The core does all the reflection — reading your annotations, deciding which members bind per language, checking each type is representable, and walking types / namespaces / bases.
- A rod (
welder::rods::pybind11::rod<>, …) is a stateless struct that supplies only the emission primitives: how to register a class, a method, a property in its framework. It never re-implements the traversal or the annotation semantics. You drive it through one entry point,welder::welder<Rod>.
Everything you write lives in the annotations. welder ships header-only, so a consuming TU brings the vocabulary in with a single include:
#include <welder/vocabulary.hpp>
#include <pybind11/pybind11.h>
#include <welder/rods/python/pybind11/rod.hpp>
Order matters
The vocabulary must be in scope before any [[=welder::…]] annotation you
write, so #include <welder/vocabulary.hpp> leads the TU (an annotated header
of yours should include it itself, for the same reason). The rod header then
brings in everything else — <meta>, welder's driver, and its framework.
Header-only, for now
An import welder; C++20 module wrapper is planned but currently deferred —
see Header-only for now for the toolchain reasons why.