Draft C++ bindings — working notes - #2
Conversation
Wire a C++ generator into the uniffi-bindgen dispatcher following the same pattern as the C# and Dart generators: an optional cpp feature pulling uniffi-bindgen-cpp, a dispatch arm selected by UNIFFI_BINDGEN_LANGUAGE, and a bindings.cpp stanza in uniffi.toml. Upstream uniffi-bindgen-cpp targets uniffi 0.29 and has no library entry point, so the dependency is pinned to a fork that rebases the in-progress uniffi 0.30 support (NordSecurity/uniffi-bindgen-cpp#59) onto uniffi_bindgen 0.31.2, exposes pub fn main(), adds a --skip-async mode (async is unsupported, their issue payjoin#51), and fixes several generator bugs surfaced by this crate's interface. Both lockfiles are regenerated to include the new dependency tree.
Provide the C++ toolchain (cmake, ninja, the stdenv compiler), libcurl and nlohmann_json for the binding tests, and the pinned msrv rust toolchain, matching the shape of the other per-language binding shells. bitcoind is exposed through BITCOIND_EXE for the integration tests.
Add payjoin-ffi/cpp following the per-language binding layout: scripts/generate_bindings.sh generates C++20 bindings in library mode (skipping the unsupported async exports) and copies the cdylib, CMakeLists.txt builds a consumable payjoin_cpp target plus ctest-registered tests, and contrib/test.sh ties it together against the maintained lockfile. The tests port the python suite: unit tests cover URI parsing, receiver and sender session persistence through an in-memory persister, cancellation, and input validation errors; integration tests drive the full v2-to-v2 payjoin against bitcoind and the payjoin test services with libcurl for OHTTP posts. Register clang-format for the handwritten test sources in treefmt and skip the generated sources in codespell.
Add a cpp workflow mirroring the other language binding workflows and register the cpp binding in the aggregate payjoin-ffi test script.
Status snapshot (2026-08-21)What exists and where:
The 4 commits (each passes checks independently):
Verified green locally (Linux):
NOT yet verified: the macOS CI leg (AppleClang C++20, dylib rpath) — first data point is payjoin#1827's checks. |
Generator fork: what it contains and why each piece existsUpstream NordSecurity/uniffi-bindgen-cpp tops out at The fork branch
Base-choice note: PR payjoin#59 branches from |
Gotchas and design notes to keep on handRegeneration / pin-bump workflow (any time the fork rev changes): # 1. edit rev = "…" in payjoin-ffi/Cargo.toml (the uniffi-bindgen-cpp dep)
# 2. regenerate BOTH lockfiles (feeds the msrv + minimal-versions CI jobs):
bash contrib/update-lock-files.sh
# 3. full check:
nix develop .#cpp -c bash ./payjoin-ffi/cpp/contrib/test.sh
nix fmt -- --ci && codespellGenerated-code layout (never commit these; all gitignored):
Dispatch convention: Generated API shapes (differ from python, matter when porting more tests):
Test infra notes:
Fragility worth knowing: the fork's wrap/deref decisions are made on string type labels ( Cosmetic known-wart: exception |
To continue — ordered checklistBefore undrafting upstream payjoin#1827:
Fork upstreaming (parallel track):
Nice-to-haves flagged during review of our own work:
Session-restore one-liners: git checkout chavic/cpp-bindings # this branch
nix develop .#cpp -c bash ./payjoin-ffi/cpp/contrib/test.sh # full suite (~12s after warm build)
# fork lives at ~/Workspace/_PayJoin/uniffi-bindgen-cpp, branch payjoin-v0.31 |
Coverage Report for CI Build 32458769663Coverage remained the same at 86.718%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
Working copy of the C++ bindings draft on this fork. The real review happens upstream in payjoin/rust-payjoin#1827 — this PR exists to hold the working notes, context, and the to-continue list in its comments so nothing lives only in a chat session. See the comments below.