@@ -143,8 +143,12 @@ all container/buffer work inside a `cppyy.cppdef` helper.
143143 int as ` void* ` ; pass ` uintptr_t ` ), and you ** must keep the source buffer alive**
144144 for the Mat's lifetime (a lifetime guard, not a copy). Distinguish "buffer you can
145145 alias" (zero-copy) from "storage you must own" (one copy).
146- - ** ` std::make_shared<T>() ` can be flaky from Python** (overload-cache sensitivity,
147- seen in control_kit) — build the object in a small C++ factory helper instead.
146+ - ** Build the object in a small C++ factory when Python can't construct it.** Three
147+ instances now: ` std::make_shared<T>() ` flaky from Python (overload-cache
148+ sensitivity, control_kit); ` make_shared ` of a specific class (control_kit); and a
149+ ** template ctor with a universal-reference default** — `Cls(NodeT&& node =
150+ NodeT())` reports "class has no public constructors" from Python (tf). One-line
151+ ` cppdef ` factory returning the object sidesteps all three.
148152
149153### 7. On-demand templates: include the ` impl ` headers
150154A precompiled ` .so ` only carries the specializations its authors compiled. To let
@@ -185,6 +189,15 @@ during transaction revert** (no Python traceback).
185189 packages all generate one. Never ` cppyy.include ` it; find the * clean* base header
186190 and load the class/plugin directly. (ros2_control's headers happen to be
187191 Cling-clean — this wall is per-package, so probe.)
192+ - ** The ORC static-initializer wall: parse succeeds, * execution* fails (vision/gtsam).**
193+ A header can ` cppyy.include ` cleanly yet the first use fault later, when Cling's ORC
194+ JIT must materialize a ** namespace-scope internal-linkage static** it can't emit —
195+ gtsam's ` static const KeyFormatter DefaultKeyFormatter ` (` Key.h ` , a non-exported
196+ ` std::function ` global; each TU emits its own init). No dependency change fixes it
197+ (it is a Cling limitation, not a missing dep). This is a distinct failure * stage*
198+ from a parse error — worth suspecting when includes pass but a symbol won't
199+ materialize; the honest fallback is §20 (the library's own Python binding for batch
200+ steps).
188201- ** Mitigation:** probe risky glue out-of-process first —
189202 ` cppyy_kit.probe_cppdef(code, include_paths=, headers=, libraries=) ` compiles it
190203 in a throwaway subprocess and returns ` (ok, message) ` without risking the main
@@ -216,6 +229,9 @@ But three neighbours are silent traps:
216229 the alias.
217230- ** Type-constant ` #define ` macros are invisible to cppyy** (vision: ` CV_8UC1 ` ,
218231 ` CV_8U ` ). Re-expose the few you need as real ` const int ` in a ` cppdef ` block.
232+ - ** A ` std::string ` inside a returned ` std::vector<std::string> ` can surface as
233+ Python ` bytes ` , not ` str ` ** (tf: ` getAllFrameNames() ` ). Decode at the kit
234+ boundary (` b.decode() ` ).
219235
220236### 12. Mirror, don't sugar
221237Patch/return the library's real classes so methods keep their C++ names (add
@@ -237,6 +253,14 @@ loop, a spin) never contends.
237253 instead: a plain-function ` std::thread ` in a ` cppdef ` helper (note ` std::async `
238254 does ** not** JIT in Cling — use ` std::thread ` ). control_kit's blocking
239255 controller-switch does exactly this.
256+ - ** The efficiency face — "let C++ own the loop; cross only on demand" (tf).** The
257+ flip side of the GIL rule is a * design win* : a library that already spins its own
258+ C++ thread is an ** ideal** cppyy target. `tf2_ros::TransformListener(spin_thread=
259+ true)` ingests ` /tf` on its own ` std::thread`, entirely off the GIL; Python only
260+ crosses on ` lookup ` . Measured ** ~ 7–14× less ingest CPU** than an equivalent Python
261+ listener (whose callback runs under the GIL), and the win ** compounds with
262+ traffic** . Prefer wrapping the library's own loop over re-implementing it in a
263+ Python thread.
240264
241265### 14. Teardown: release global-state C++ objects before Python finalizes
242266A cppyy process ends by running two teardown mechanisms with ** no ordering
@@ -269,6 +293,13 @@ with no Python traceback**, *after* all useful work is done.
269293 process-global C++ state (bt, pcl) register nothing: their objects are
270294 per-instance and RAII-released on scope exit, and the JIT'd namespaces are
271295 Cling's to tear down. ` test/test_clean_exit.py ` is the regression tripwire.
296+ - ** A C++ object owning an executor + ` std::thread ` is the same hazard (tf, 3rd
297+ instance).** ` rclcppyy.tf ` 's C++ TransformListener owns a spinning executor +
298+ thread; ` register_teardown ` a callback that drops it (its dtor cancels the
299+ executor and joins the thread) so it releases ** before** ` shutdown_rclcpp ` (LIFO
300+ order is correct). Exit 0 confirmed. Same rule as the pluginlib instance/loader
301+ ` reset() ` in §19: anything owning threads/executors/global state gets an ordered
302+ teardown.
272303
273304### 15. First-use JIT: make it visible, move it with ` warmup() `
274305The first time a given C++ signature is crossed, cppyy JIT-compiles a call wrapper
@@ -390,7 +421,19 @@ Before investing in a kit, a couple of one-line greps tell you what's separable:
390421 first. When blocked * and* the work is ** batch** (not a hot loop), the library's own
391422 ** Python binding is a legitimate fallback** for that step — cppyy is not the only
392423 tool, and a kit can mix (drive the hot C++ path via cppyy, use the binding for a
393- one-shot batch step).
424+ one-shot batch step). (2nd instance of this rule after the gtsam batch step below.)
425+ - ** Probe layered blockers one at a time, and know when to stop.** gtsam via cppyy
426+ is the worked example: fixing the boost blocker (add headers) only exposed a
427+ ` GTSAM_USE_TBB ` → tbb-headers blocker, which when fixed exposed the Cling ** ORC
428+ static-init wall** (§9) — a * Cling limitation no dependency fixes* . Peel one layer,
429+ re-probe out-of-process; when the bottom layer is a Cling limitation rather than a
430+ missing dep, stop and take the Python-binding fallback for that batch step. Don't
431+ keep adding dependencies against a wall that isn't a dependency problem.
432+ - ** Distrust environment shims, prefer the native binary.** A library's console-
433+ script entry point can be broken in an env while its native binary works (vision:
434+ the ` rerun ` console script vs spawning the viewer binary by its executable path).
435+ When a Python-package CLI shim misbehaves, resolve and invoke the real executable
436+ directly rather than assuming the library is broken.
394437
395438### 21. Vendored-source direct-compile (when there's no package)
396439For a small, well-understood subset of a library that ships no conda package
@@ -399,6 +442,19 @@ with a direct `$CXX` invocation into a `.so` — this beats fighting the library
399442CMake/ExternalProject. It generalizes the L2 lowering recipe (` build_l2_node ` →
400443` build_dbow2 ` ): a reproducible build script, artifact gitignored, env-version tagged.
401444
445+ ### 22. Overload mis-resolution: a compilable-but-WRONG overload that crashes
446+ Distinct from the parse/execution faults (§9): with a ** thicket of overloads** , cppyy
447+ can pick one that ** compiles and runs but is the wrong one** , crashing at runtime
448+ (bus error, no Python traceback). tf: `tf2_ros::Buffer::lookupTransform(target,
449+ source, TimePoint)` resolved into the ` rclcpp::Time` +timeout ` canTransform` path,
450+ which called ` rclcpp::Clock::now() ` and bus-errored. The trap is worst when a class
451+ mixes a ` using ` -imported base form with timeout/clock forms of the same name.
452+ - ** Rule:** prefer the ** single-signature base class** (here ` tf2::BufferCore ` , one
453+ unambiguous ` lookupTransform ` ) over the overload-heavy derived one; or wrap the
454+ exact call you want in a ` cppdef ` free function so C++ overload resolution — not
455+ cppyy's — picks it. Probe a suspicious overloaded call out-of-process; a
456+ wrong-overload crash gives you nothing to read in Python.
457+
402458---
403459
404460## Today vs L1 ("freeze") — L1 now WORKS
0 commit comments