Run your first check¶
Best first run: compare two shared libraries with their public headers — it gives abicheck the most evidence to work with (see how much evidence you need below).
Start with the compare-release workflow example — a small,
purpose-built library (mathutils) that ships two releases, the second of
which quietly drops an exported function:
# Build both releases as shared libraries
python3 build_shared_lib.py -fPIC -g v1/mathutils.c -o libmathutils_v1.so
python3 build_shared_lib.py -fPIC -g v2/mathutils.c -o libmathutils_v2.so
# Compare, giving abicheck each side's public header for the strongest evidence
abicheck compare libmathutils_v1.so libmathutils_v2.so \
--header old=v1/mathutils.h --header new=v2/mathutils.h
# Verdict: BREAKING (func_removed: subtract)
examples/workflows/compare-release/README.md walks through the same run in
more detail, and CI executes those exact commands on every change
(skills-src/evaluation/validation/scripts/run_workflow_examples.py), so what you read is what
runs.
Looking for a catalogue rather than a tutorial? The repository also carries 208 calibration cases under
examples/case*/— one per compatibility mechanism, used to calibrate the detectors rather than to teach the CLI. Browse them in the Compatibility Catalog, which indexes them by rule, scenario kind, ecosystem, operation, evidence level, language, and verdict.No
castxml? The command above will fail withcastxml not found. Either install castxml, or run the same comparison without headers by dropping the header flags — since these libraries were built with-g, abicheck still picks up their DWARF debug info and catches the removed symbol from that (falling back further to symbols-only only if no debug info is present):
For your own library:
abicheck compare libfoo.so.1 libfoo.so.2 \
--header old=include/v1/foo.h --header new=include/v2/foo.h
If the header is the same for both versions:
You can also pass a header directory (recursive scan for *.h, *.hpp, ...):
If no headers are provided for ELF inputs, abicheck uses DWARF debug info if
available (e.g. libraries built with -g, like the ones above), falling back to
symbols-only mode only when no debug info can be found either — either way it
prints a warning, since less evidence means a weaker analysis that may miss
type/signature ABI breaks. See How much evidence do you need?
below and Evidence & Detectability for the
full L0–L5 model.
How much evidence do you need?¶
Binary-only detects exported-symbol changes (add/remove, SONAME, visibility).
Adding debug info catches layout and calling-convention breaks; adding headers
adds the full public API surface and scopes out internal types; adding build
and source context catches the facts that never reach the binary at all
(macros, default-argument values, uninstantiated templates). Each source is
additive — more evidence only ever finds more, never hides an artifact-proven
break. Run abicheck dump libfoo.so --dry-run to see which layers abicheck
found for a binary. For the full model, the exact L0–L5 layer table, and a
worked example, see Evidence & Detectability
and What Each Level Sees.
Next¶
➡️ Understand your first report
Have no second release to compare against yet? See the audit-release
workflow example instead —
examples/workflows/audit-release/README.md checks a single build against
itself for things like an accidentally-exported symbol, no baseline
required.