Skip to content

08 — Tack welding a third-party library

Source: examples/cookbook/08-tack-welding.

Everything so far assumed you can annotate the C++. When you can't — the types come from a library you don't control — swap the carriage: welder's traversal driver is the third template argument of welder::welder, and welder::tack_welding_carriage ignores the missing weld markers, binding greedily (Extending welder has the carriage model).

The "vendor" library

vecmath.hpp is deliberately plain C++ — structs, operators, free functions, constants, a nested namespace, and zero welder annotations.

The binding TU

#include "vecmath.hpp" // the "third-party" header — zero welder annotations

PYBIND11_MODULE(fastvec, m) {
    using tack = welder::welder<welder::rods::pybind11::rod<>,
                                welder::naming::none,
                                welder::tack_welding_carriage>;
    tack::weld_namespace<^^vecmath>(m);
}

Under tack welding every reflectable type/function/variable participates, nested namespaces recurse greedily into submodules, and public bases are flattened. Note Vec3 appearing in the library's own signatures (dot, cross) with no annotation and no hatch: the tack carriage's registration oracle accepts class types its own greedy pass registers. Two things do not change:

  • The bindability gate still holds. A genuinely non-representable type stays a compile error, as does a forward-declared (incomplete) type the walk cannot register; for a type registered elsewhere (hand-bound, another library's bindings), the trust_bindable hatches remain the escape valve.
  • Marks are still honored. If the header does carry a mark::exclude (perhaps via a patch), it is respected.

Mixing stitch and tack

The tack welder is just another welder::welder alias — use the default (stitch) welder for your own annotated types and a tack welder for the vendor namespace, in the same module. And when greedy is too greedy, Recipe 09 subclasses the tack resolution to prune the library's detail namespace and underscore internals.

What the check asserts

Vec3 binds with its synthesized aggregate constructor, methods, and __add__/__eq__ operators; cross and EPSILON arrive as module members; vecmath::units became the fastvec.units submodule — all without touching the vendor header.