ABI stability
What stays fixed across releases, what is mechanically enforced, and what is only a stated intention.
---This document is the compatibility contract for libxtc, and it is deliberately written in two voices:
- ENFORCED – a gate in
make check/ CI fails if the rule is broken. Every such rule names the gate. - POLICY (not mechanically enforced) – the maintainer’s stated intention. Nothing in the tree checks it. Treat it as a promise backed by review, not by tooling.
An earlier version of this page described symbol-version maps, capability strings, a prior-release compat suite, and a trace-shape diff suite as if they existed. They did not, and do not. They have been removed rather than left as false advertising; what remains is what a packager can verify in the tree.
Version numbering (POLICY)
Versioning is MAJOR.MINOR.PATCH. The intent:
- PATCH (
1.49.x). Bug fixes only. Same ABI, same on-disk formats, same trace shape. Drop-in replacement. -
MINOR (
1.x.0). New features, new APIs. Additive only: nothing removed, nothing renamed. NewXTC_E_*codes only at the end of the enum; existing codes never change value. New lock modes never inserted in the middle of an enum.The additive-ABI promise is currently BROKEN for caller-allocated option and info structs, which have grown (and in two cases had fields inserted mid-struct) during 1.x. This is a real defect, not a footnote: see Known issues for the measured sizes, the two severity classes, and the consumer rule. Until it is addressed, recompile consumers against the headers of the exact minor whose library they link.
- MAJOR (
x.0.0). Breaking changes allowed. Cadence is intentionally slow.
No tooling verifies any of this. There is no release gate that diffs
the exported symbol set, the struct layouts, or the function
signatures against the previous tag. If you need that guarantee for a
packaging decision, run abidiff/abi-compliance-checker yourself
between the two tags you care about; libxtc does not do it for you.
What the shared library actually exports (ENFORCED)
There is no per-symbol version map. dist/libxtc.map is a single
unnamed version node, so every exported symbol is unversioned; the
file says so in its own header comment, and defers per-symbol
versioning to a later day. Consumers link against the SONAME
(libxtc.so.MAJOR), and the policy above – not the linker – governs
compatibility.
What is enforced, by test/m0/test_symbols.sh in make check and
CI:
[C5]every symbol defined inlibxtc.aisxtc_*,__xtc_*, or_-prefixed. No stray global names.[C6]installed public headers do not#definestandard or bare identifiers.[C7]installed public headers declare no__-prefixed internal function, except the small allowlist a public macro expands to.[C8]the shared library’s dynamic symbol table is exactlyxtc_*plus that same macro-backed allowlist – so the whole__os_*substrate and every other internal stays private.[C8]also asserts the allowlist agrees with[C7]’s.
Per-platform link recipes (in dist/configure.ac):
- ELF (Linux, the BSDs, illumos):
-Wl,-soname,libxtc.so.MAJORplus-Wl,--version-script=dist/libxtc.map(export restriction, not symbol versioning). - macOS:
-install_name,-compatibility_version MAJOR.0,-current_version FULL, and-Wl,-exported_symbols_list,libxtc.exp– the Mach-O equivalent of the ELF export list, generated from the archive bydist/Makefile.in. - Windows: the per-commit build is
xtc.lib(static). There is no hand-curatedxtc.defand no ordinal stability commitment.
Man-page and header agreement (ENFORCED)
The documentation side of the contract is gated:
test/m0/test_man_coverage.sh– everyPUBLIC:function across the installed header set is documented in someman3page.test/m0/test_man_signatures.sh– a function’s page mentions every parameter name from its declaration and documents the return contract.test/m0/test_man_lint.sh– mdoc lints clean.test/m0/test_docs_abi.sh– every tool, path, and gate script this page cites exists in the tree, and the page does not claim machinery that is absent. (That gate was added because this page previously described five nonexistent files and it passed anyway.)test/docs/test_doc_snippets.sh– every code snippet in the docs compiles and runs against the freshly built library.
Frozen surfaces (POLICY)
The lock layer is the widest-consumed surface, so it is committed
frozen: xtc_lwlock_t / xtc_lwlock_mode_t and the xtc_lwlock_*
entry points; xtc_lrlock_t and xtc_lrlock_*; xtc_lockmgr_t,
xtc_locker_t, xtc_lock_mode_t, xtc_lockmgr_opts_t,
xtc_lockmgr_stat_t, xtc_lock_req_t and the xtc_lockmgr_* /
xtc_lock_* entry points. Both the signatures and the layout of
those option/stat structs are meant to hold across 1.x.
Verified by hand for this release: none of those structs has changed
size or field order since v1.0.0. But no gate checks it, and the
struct-growth defect above shows that hand review is not sufficient on
its own. If a new optional field is ever needed there, it must go
through a new struct or a versioned _ex entry point, never an
in-place layout change.
Deprecation lifecycle (POLICY – machinery NOT present)
The intended lifecycle for removing a public API, one minor release per stage at minimum:
| Stage | Behaviour | Intended signal |
|---|---|---|
| 1. Live | Documented, supported. | Nothing. |
| 2. Soft-deprecated | Documented, supported. | Doc note. |
| 3. Deprecated | Supported, discouraged. | Compiler warning. |
| 4. Default-off | Opt-in build flag required. | Build error without the flag. |
| 5. Removed | Header #error‘d; symbol absent. |
Build error always. |
None of the compiler/runtime machinery exists yet. There is no
XTC_DEPRECATED_SOFT or XTC_DEPRECATED attribute macro in the
headers, no xtc_cfg.warn_deprecated knob, and no
-DXTC_ENABLE_DEPRECATED build mode. Nothing has been deprecated in
1.x, so the machinery has not been needed; it will be added with the
first real deprecation. Until then, stages 2-4 are documentation
notes only.
No capability query API
Applications sometimes want to ask the library what it can do rather
than hard-coding a version. libxtc has no such API today – there
is no xtc_have_capability() and no capability-string table, in any
form. (An earlier version of this page showed example calls to one.
They never compiled.)
What you can query today, from the public API:
xtc_version_string()/ theXTC_VERSION_*macros – the version.xtc_runtime_info()– loop count, CPU counts, NUMA node count.- The configure-time
xtc_config.hdefines (XTC_IO_BACKEND_*,XTC_HAVE_*) – which backend a given build selected.
Because the I/O backend and coroutine substrate are chosen at configure time, not runtime, “which backend am I on” is a compile-time fact for a statically linked consumer. A consumer that swaps a shared libxtc underneath itself has no runtime way to ask, and should pin the minor.
On-disk and wire formats
libxtc defines no database format. It does emit:
- The
xtc_tailevent-trace dump (xtc_tail_dump), a 24-byte header of magic + version + flags + count + base timestamp, read bytools/xtc-tail.py. - The dial9 wire form of the same trace (
xtc_tail_dump_dial9), magicTRC\0+ version. xtc_dump(fd)– a human-readable diagnostic dump, not a parsed format, with no compatibility commitment.
Both trace formats carry a version field, so a reader can reject or
adapt. POLICY: a format change bumps that field rather than
silently reinterpreting bytes. There is no xtcdump or xtcadmin
tool, no flight-recorder *.flt format, and no admin-socket protocol
in this tree; earlier claims about them were removed.
Trace shape (POLICY)
Dashboards and runbooks bind to event names. Intended: event names stable across minors, new event kinds may be added in a minor, renaming or removing one is a major change. No suite captures or diffs trace shape, so this rests on review.
Long-term support (POLICY)
Informal, and stated as intent rather than commitment: security fixes
go to the current release; an LTS window on a previous major will be
defined if and when there is a second major. There is no
xtc-security@ list, no published embargo policy, and no backport
branch in this tree yet.
Downgrades (POLICY). A downgrade – running an older release against data or state a newer one has written (for example a sqlxtc store) – is supported only between LTS releases, and only to the immediately previous LTS. There are no LTS releases yet, so no downgrade is supported: an on-disk format may change in any minor, and the release that changes it says so in KNOWN_ISSUES. Upgrades are supported: a release reads what earlier releases wrote unless its notes say otherwise.
See also
- Known issues – the struct-growth ABI defect, in detail, with measurements.
adr/– architecture decision records.- Testing – how the enforced gates are run.