Skip to content

Inline ABI namespace jinja2::v2 and its release gates (0076 PR-2) - #604

Merged
rmorozov merged 7 commits into
masterfrom
claude/project-thread-w97e4u
Oct 19, 2026
Merged

rmorozov merged 7 commits into
masterfrom
claude/project-thread-w97e4u

Conversation

@rmorozov

@rmorozov rmorozov commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

Requested by Ruslan · project thread

Before: a program compiled against 1.x headers could link against a 2.x library, or the reverse, and fail at run time. Nothing checked the SOVERSION policy.

After: everything in include/ and src/ lives in jinja2::v2, an inline namespace. Users still write jinja2::Value, but the major version is part of every mangled name, so mixing 1.x and 2.x fails at link time. CI checks this four ways: nm, a negative link probe, the installed SONAME, and an abidiff report on one shared build per C++ standard.

The tag is written out in the source as namespace jinja2 { inline namespace v2 {, not hidden behind a macro. scripts/abi_namespace.py writes it and the format-check job runs it with --check, so the 3.0 retag is one run of the script (plan 0076, sections 1-2).

How

  1. c4a0aaf5 adds scripts/abi_namespace.py.
    • It brace-matches each namespace jinja2 opening, skipping comments, literals and raw strings, and wraps the body in inline namespace v2.
    • A nested namespace jinja2::x becomes three namespaces, because C++17 cannot nest an inline namespace in that form.
    • Any spelling it does not rewrite is reported as an error.
  2. ae4649c9 is pure script output over 90 files, listed in .git-blame-ignore-revs.
    • Steward: keep this SHA by merging, not squashing.
    • If the train adds or conflicts on namespace jinja2 lines, re-run the script on the integration branch.
  3. a5533287 adds the gates:
    • nm test. CTest jinja2cpp_abi_namespace fails on any jinja2 symbol outside v2, or on a global xyz.
    • Link probes in test/package: abi_probe_v2 must link and run, and abi_probe_v1 (1.x mangling) must not link.
    • SONAME check in check_package.cmake: the installed SONAME must carry SOVERSION.
    • Version asserts now require major 2.
    • README: a "Compatibility and versioning" section, and find_package(jinja2cpp 2).
    • abidiff job.
      • One shared RelWithDebInfo build per standard dumps the ABI with abidw; libabigail is added to the SBOM.
      • scripts/abi_report.sh compares that dump with the previous one. Until the RC it only reports, against the last master build.
      • From the RC the comparison is against the baselines committed in abi/ (task 0285). A break then fails unless SOVERSION was bumped and the baseline replaced in the same PR.
  4. 577860d3: verifier fixes. 1c84b543: MSVC fix. ede67072: Codex fixes. c3cc4ff4: merged master (train 26) and re-ran the script, which wrapped the new big_int.h.

Deliberate divergences from the approved plan:

  • abidiff suppressions cover only the vendored jinja2::v2::detail::xyz, robin_hood and lexertk. jinja2::v2::detail stays checked, because inline header code calls exported detail functions.
  • abidiff rows. C++20 runs on the gcc-12 row instead of gcc-14, and C++17 on clang-18, the only C++17 shared row. With this choice the remaining Release rows still cover every value pairwise.
  • "Break" means any change left after --no-added-syms, not only abidiff exit bit 8. abidiff reports a changed layout, such as a new Settings field, with bit 4.
  • MSVC does not implement CWG 2061.
    • On MSVC, namespace jinja2 { namespace detail { declares a second jinja2::detail instead of reopening jinja2::v2::detail.
    • The tests therefore define 1.x-style detail::Reflector specialisations by their qualified name, and the README tells users to do the same.
    • Specialising directly inside namespace jinja2 { ... } still works on MSVC.

Follow-up filed: 0285, commit the ABI baselines at the RC. PR-1 filed 0259, 0260 and 0261. The jbcoe upstream issue is postponed, per Ruslan.

Validation

  • Script. Re-running it on c4a0aaf5 reproduces ae4649c9 exactly, --check exits 0, and clang-format is clean.
  • Local builds. All tests, including the nm test, pass on:
    • GCC 13 Debug static
    • GCC 13 RelWithDebInfo shared
    • Clang 18 Debug shared, C++20
    • Clang 18 RelWithDebInfo shared, C++17
    • Clang 18 ASan+UBSan
  • CI. All 42 checks are green on c3cc4ff4: Linux, MSVC, macOS, sanitizers, Conan, fuzz and CodeQL.
  • Package checks. check_package.cmake passes 5/5 for static and shared installs. The v1 probe fails with the undefined reference to jinja2::operator==.
  • nm gate. It counts 122,245 jinja2::v2 symbols and none outside v2. On the old, untagged library it fails.
  • abi_report.sh.
    • An identical dump passes.
    • A pure addition passes.
    • A layout change fails.
    • Removed symbols fail.
    • A baseline with a different SONAME fails.
  • Preflight. scripts/preflight.sh --perf passes, with instruction counts unchanged (±0.04%). The Unicode/HTML generators pass --check under Python 3.12.

Roles: verifier and ci-triage. The verifier ran 1 round and found 2 blocking issues, both fixed in 577860d3: the generators were out of sync with the wrapped headers, and the abidiff gate missed layout changes.

Red CI pushes: 2.

  • 577860d3: MSVC failed on tests that reopened jinja2::detail (CWG 2061).
  • ede67072: the PR merge ref picked up train 26's new big_int.h in plain namespace jinja2, which MSVC rejected and nm and the script check flagged. Fixed by c3cc4ff4.

Codex: 2 findings, both P2. 2 fixed in ede67072, 0 declined:

  • The SONAME check now reads SOVERSION.
  • The baseline's SONAME must match the library's.

The requested security review did not start; the code review ran.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ua8ABM1TRsAvso2sWGHFSw

…ce v2 (0076)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ua8ABM1TRsAvso2sWGHFSw
Pure output of scripts/abi_namespace.py; no hand edits. Listed in
.git-blame-ignore-revs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ua8ABM1TRsAvso2sWGHFSw
…abidiff (0076)

- format-check runs scripts/abi_namespace.py --check
- CTest jinja2cpp_abi_namespace: no jinja2 symbol outside v2, no global xyz
- test/package: abi_probe_v2 links, abi_probe_v1 (1.x mangling) must not
- check_package.cmake checks the installed SONAME; version asserts need major 2
- linux-build: one shared RelWithDebInfo row per standard dumps the ABI with
  abidw and reports abidiff against the last master build (baselines at the
  RC, task 0285)
- README: Compatibility and versioning; find_package(jinja2cpp 2)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ua8ABM1TRsAvso2sWGHFSw
…anges

- gen_html_entities/unicode_case/unicode_tables/unicode_printable emit the
  inline namespace v2 form, so their --check matches the wrapped headers
- abi_report.sh: any change left after --no-added-syms is a break (abidiff
  reports a changed layout with bit 4, not 8); artifact uploaded on failure
- abi_namespace.py rejects spellings it does not rewrite (indented, one-line)
- docs/dependencies.md and SBOM name jinja2::v2::detail::xyz

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ua8ABM1TRsAvso2sWGHFSw
MSVC does not implement CWG 2061: reopening namespace detail inside
namespace jinja2 declares a new jinja2::detail beside jinja2::v2::detail.
containers_api_test and node_arena_test now use the qualified form, and the
README tells 1.x detail::Reflector users to do the same.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ua8ABM1TRsAvso2sWGHFSw

Copy link
Copy Markdown
Member Author

@codex review

@codex security review (the lexer, parser and evaluator files change only by the generated inline namespace v2 lines in commit ae4649c; the hand-written changes are the gates, tests, CI and docs)


Generated by Claude Code

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-19T03:44:54.976564Z 1c84b54 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1c84b543d3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread test/package/check_package.cmake Outdated
Comment thread scripts/abi_report.sh Outdated
- check_package.cmake reads SOVERSION from CMakeLists.txt instead of using the
  project major, so a within-2.x SOVERSION bump installs and checks cleanly
- abi_report.sh gate fails while the committed baseline's SONAME differs from
  the library's, so a SOVERSION bump cannot land without its new baseline

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ua8ABM1TRsAvso2sWGHFSw
The merge brought include/jinja2cpp/big_int.h in plain namespace jinja2;
scripts/abi_namespace.py wrapped it, which MSVC needs (CWG 2061).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ua8ABM1TRsAvso2sWGHFSw

Copy link
Copy Markdown
Member Author

MSVC C++20 shared went red on ede6707 because PR CI builds the merge with master. Train 26 had just added include/jinja2cpp/big_int.h in plain namespace jinja2, and MSVC treats that as a second jinja2::detail (C2872 "ambiguous"; it does not implement CWG 2061). This is the case scripts/abi_namespace.py --check exists to catch. I merged master and re-ran the script, which wrapped big_int.h. The static Debug build and all tests pass locally, preflight is clean, and the merge is pushed. Steward: any PR that lands before this one and adds a namespace jinja2 needs the same script run on the train branch.


Generated by Claude Code

rmorozov pushed a commit that referenced this pull request Oct 19, 2026
rmorozov added a commit that referenced this pull request Oct 19, 2026
Merge train 28: dict keys of any hashable type (#594), ABI namespace jinja2::v2 (#604)
@rmorozov
rmorozov merged commit 818df46 into master Oct 19, 2026
42 checks passed
rmorozov pushed a commit that referenced this pull request Oct 19, 2026
One ResourceLimitError (src/engine_errors.h) serves Settings::Limits, named by
its field, and the built-in caps, without one; CurrentExceptionToError reports
both as ResourceLimitExceeded with the field as extraParams[1] when present,
so Render's own catch for it is gone. The built-in sequence cap throws it
instead of std::length_error. exception.h, engine_errors.h and
error_boundary.h are wrapped in v2 by scripts/abi_namespace.py.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013sRZrdyAGVT1hBgARAkNAE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants