Skip to content

Getting Started

abicheck compares two versions of a C/C++ shared library and tells you whether existing binaries will break. It supports ELF (Linux), PE/COFF (Windows), and Mach-O (macOS) binaries.

On all platforms it provides binary metadata analysis (exports, imports, dependencies) and header AST analysis (via castxml). Debug info cross-check uses DWARF (Linux, macOS) and PDB (Windows).

Platforms: Linux, Windows, macOS.


1) Install abicheck

pip install abicheck
# or
conda install -c conda-forge abicheck

Requirements

  • Python 3.10+
  • castxml + C/C++ compiler — for header AST analysis (optional but recommended, all platforms)

All Python dependencies (pyelftools, pefile, macholib) come with abicheck install. Without castxml, abicheck still works in binary-only mode.

Option A: system packages

# Ubuntu / Debian
sudo apt-get update && sudo apt-get install -y castxml gcc g++
# macOS
brew install castxml
# plus Xcode Command Line Tools for clang
# create env and install abicheck (recipe includes required analysis deps)
# Python >= 3.10 is required; any supported version works
conda create -n abicheck -c conda-forge python=3.12 abicheck
conda activate abicheck

No extra manual dependency installation is required when using the conda-forge package.

Install from source

git clone https://github.com/napetrov/abicheck.git
cd abicheck
pip install -e .

2) First check (using repo examples)

The repo includes 63 ABI scenario examples with paired v1/v2 sources and headers:

cd examples/case01_symbol_removal
# Build v1 and v2 shared libraries
gcc -shared -fPIC -g v1.c -o libv1.so
gcc -shared -fPIC -g v2.c -o libv2.so
# Compare
abicheck compare libv1.so libv2.so --old-header v1.h --new-header v2.h
# Verdict: BREAKING (symbol 'helper' was removed)

For your own library:

abicheck compare libfoo.so.1 libfoo.so.2 \
  --old-header include/v1/foo.h --new-header include/v2/foo.h

If the header is the same for both versions:

abicheck compare libfoo.so.1 libfoo.so.2 -H include/foo.h

You can also pass a header directory (recursive scan for *.h, *.hpp, ...):

abicheck compare libfoo.so.1 libfoo.so.2 -H include/

If no headers are provided for ELF inputs, abicheck falls back to symbols-only mode and prints a warning (weaker analysis: may miss type/signature ABI breaks).


3) Output formats

abicheck supports four output formats: markdown (default), json, sarif, html.

Markdown (default, printed to stdout):

abicheck compare libfoo.so.1 libfoo.so.2 -H foo.h

JSON — machine-readable, includes precise verdict field:

abicheck compare libfoo.so.1 libfoo.so.2 -H foo.h --format json -o result.json

SARIF — for GitHub Code Scanning:

abicheck compare libfoo.so.1 libfoo.so.2 -H foo.h --format sarif -o abi.sarif

HTML — standalone human-readable report:

abicheck compare libfoo.so.1 libfoo.so.2 -H foo.h --format html -o report.html

4) Snapshot workflow (for CI baselines)

Save a snapshot once per release, then compare against new builds without re-dumping:

# Save baseline (header is baked into the snapshot)
abicheck dump libfoo.so -H include/foo.h --version 1.0 -o baseline.json
# Compare saved baseline against current build
abicheck compare baseline.json ./build/libfoo.so \
  --new-header include/foo.h --new-version 2.0-dev
# Or compare two snapshots (no headers needed — already baked in)
abicheck compare old.json new.json

compare auto-detects each input: .so files are dumped on-the-fly, .json snapshots are loaded directly. You can mix them freely.

Language mode

Use --lang c for pure C libraries (default is c++):

abicheck dump libfoo.so -H foo.h --lang c -o snap.json

Cross-compilation

When analysing libraries built for a different architecture:

abicheck dump libfoo.so -H include/foo.h \
  --gcc-prefix aarch64-linux-gnu- \
  --sysroot /opt/sysroots/aarch64 \
  -o snap.json

Available flags: --gcc-path, --gcc-prefix, --gcc-options, --sysroot, --nostdinc.

Verbose output

abicheck compare old.json new.json -v

5) Application compatibility check

Check whether your application is affected by a library update — filtering out irrelevant changes:

abicheck appcompat ./myapp libfoo.so.1 libfoo.so.2 -H include/foo.h

This parses your application binary to find which library symbols it actually uses, then shows only the changes that matter. If the library removed a function your app never calls, it won't appear in the report.

Quick symbol availability check (no old library needed):

abicheck appcompat ./myapp --check-against libfoo.so.2

See Application Compatibility for the full reference.


6) Exit codes and CI

Exit code Verdict Meaning
0 NO_CHANGE / COMPATIBLE / COMPATIBLE_WITH_RISK Safe — no binary ABI break
1 Tool/runtime error
2 API_BREAK Source-level API break (binary still works)
4 BREAKING Binary ABI break

Full reference (including compat mode): Exit Codes

GitHub Actions example

Save a baseline once at release time, then compare every new build:

# Release step — save baseline as an artifact
abicheck dump ./build/libfoo.so -H include/foo.h \
  --version 1.0 -o abi-baseline.json
# Upload abi-baseline.json as a release artifact
# CI step — compare new build against saved baseline
steps:
  - name: Download ABI baseline
    uses: actions/download-artifact@v4
    with:
      name: abi-baseline

  - name: Compare ABI
    run: |
      abicheck compare abi-baseline.json ./build/libfoo.so \
        --new-header include/foo.h \
        --format sarif -o abi.sarif

  - uses: github/codeql-action/upload-sarif@v3
    if: always()
    with:
      sarif_file: abi.sarif

Next steps