Platform Support¶
abicheck runs on Linux, macOS, and Windows and can analyze binaries from any of these platforms. However, the depth of analysis depends on the host platform and whether headers are available.
Quick Reference: What Works Where¶
Scanning Linux ELF binaries¶
| Host OS | Symbol diff | Type/param diff | Requires |
|---|---|---|---|
| Linux ✅ | ✅ Full | ✅ Full | castxml, g++/gcc |
| macOS | ✅ Yes | ❌ No | — |
| Windows | ✅ Yes | ❌ No | — |
Best results: run on Linux with headers provided.
Scanning Windows PE (DLL) binaries¶
| Host OS | Symbol diff | Type/param diff | Requires |
|---|---|---|---|
| Linux | ✅ Yes | ❌ No | pefile |
| macOS | ✅ Yes | ❌ No | pefile |
| Windows | ✅ Yes | ✅ Yes | castxml + cl.exe |
Scanning macOS Mach-O (dylib) binaries¶
| Host OS | Symbol diff | Type/param diff | Requires |
|---|---|---|---|
| Linux | ✅ Yes | ❌ No | macholib |
| macOS | ✅ Yes | ✅ Yes | castxml (Xcode clang) |
| Windows | ✅ Yes | ❌ No | macholib |
What "Symbols Only" Mode Means¶
When scanning a binary without headers, or scanning a non-native binary cross-platform, abicheck operates in symbol-table mode:
✅ Detected:
- Function added / removed (func_added, func_removed)
- SONAME changed (soname_changed)
- Symbol visibility changed (symbol_visibility_changed)
- Variable added / removed
❌ Not detected (requires type information from headers + castxml):
- Parameter type changes (func_params_changed)
- Return type changes (func_return_type_changed)
- Struct/class layout changes (type_size_changed, type_field_*)
- vtable changes (type_vtable_changed)
- Inline/noexcept changes
Recommendation: for complete ABI analysis, always provide -H <header_dir> and run on the
native platform (Linux for ELF, macOS for Mach-O, Windows for PE).
Cross-Platform Examples¶
Scan a Windows DLL from Linux¶
# Symbol-level diff (works cross-platform)
abicheck compare mylib_v1.dll mylib_v2.dll
# With headers (only useful if castxml+cl.exe is available)
abicheck compare mylib_v1.dll mylib_v2.dll \
-H include/
What you get: func_removed, func_added, ordinal changes.
What you miss: parameter type changes, struct layout changes.
Scan a macOS dylib from Linux¶
What you get: exported symbol diff. What you miss: type-level analysis (no DWARF walk cross-platform today).
Scan a Linux .so from macOS¶
ELF parsing is pure Python — works on macOS. DWARF walk also works.
Full type analysis requires castxml and headers available on the host.
GitHub Actions: Multi-Platform CI¶
To get full analysis on each platform:
jobs:
abi-check:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install abicheck (source)
run: pip install -e .
- name: Install castxml (Linux/macOS only)
if: runner.os != 'Windows'
run: |
# sudo apt-get install -y castxml # Ubuntu
# brew install castxml # macOS
- name: ABI check
run: |
abicheck compare -lib mylib \
-old old/libmylib.so -new new/libmylib.so \
-H include/
Known Limitations by Platform¶
Windows host¶
castxmlwithcl.exebackend is untested in CI — may work but is not validated- MSVC vtable layout differs from Itanium ABI; vtable diff results may be inaccurate
__stdcall/__cdeclcalling-convention changes appear asfunc_removed + func_added(mangled-name churn) — no dedicated change kind; see #50 below- Tracked: abicc upstream issues #9, #50, #56, #121
macOS host¶
- ARM64 Apple AAPCS differs from Itanium for small structs (≤16 bytes passed in registers)
install_name(LC_ID_DYLIB, macOS SONAME equivalent) changes are tracked and emitSONAME_CHANGED- Two-level namespace (
LC_LOAD_DYLIB) not fully analyzed - Tracked: abicc upstream issues #116, #119
All platforms (symbols-only mode)¶
int → longparameter change: mangled name changes → detected asfunc_removed + func_added(notfunc_params_changed) when headers are absent- Template inner-type changes (
std::vector<T>with changedT) — not detected (tracked: #38)
Dependency Summary¶
| Feature | Required tools | pip / system install | conda-forge install |
|---|---|---|---|
| ELF analysis | pyelftools |
pip install -e . |
conda install -c conda-forge abicheck |
| PE analysis | pefile |
pip install -e . |
conda install -c conda-forge abicheck |
| Mach-O analysis | macholib |
pip install -e . |
conda install -c conda-forge abicheck |
| Type/param analysis (Linux) | castxml + C/C++ compiler |
pip install -e . + apt/yum (castxml, gcc/g++) |
conda install -c conda-forge abicheck |
| Type/param analysis (macOS) | castxml + Apple toolchain |
pip install -e . + brew install castxml (+ Xcode CLT) |
conda install -c conda-forge abicheck |
| Type/param analysis (Windows) | castxml + cl.exe |
pip install -e . + Visual Studio Build Tools + castxml |
conda install -c conda-forge abicheck |
For conda-based workflows, install only abicheck from conda-forge.
Recipe dependencies pull required analysis tooling automatically.
Windows Toolchain Support Matrix¶
| Toolchain | castxml backend | Type/param diff | Calling-convention tracking | Status | Notes |
|---|---|---|---|---|---|
| MinGW (GCC) | --castxml-cc-gnu gcc |
✅ Yes | ⚠️ Partial (__cdecl/__stdcall not a dedicated kind, #50) |
Experimental | Covered by CI smoke tests; full MinGW integration coverage on windows-latest is best-effort and not guaranteed on every run. |
MSVC (cl.exe) |
--castxml-cc-msvc cl.exe |
✅ Yes | ⚠️ Partial (#9, #50) | Untested in CI | May work locally with Visual Studio Build Tools; ABI details differ from Itanium assumptions in several detectors. |
Known Limitations (Windows)¶
- #9 (MSVC headers / Windows SDK edge cases): castxml+
cl.exehandles common cases, but complex SDK-specific declarations are not yet validated in project CI. - #50 (calling conventions):
__stdcall/__cdecldeltas are represented as mangled-name churn (func_removed + func_added) instead of a dedicated calling-convention change kind. - #56 (PE visibility semantics):
__declspec(dllexport/dllimport)transitions are currently reflected at symbol-level only; no dedicated PE export-visibility change kind. - #121 (MinGW-specific behavior): MinGW export/import edge-cases (import libs, ordinals, toolchain flags) are only partially covered by current smoke/integration tests.
macOS ARM64 — Known ABI Differences¶
ARM64 (Apple Silicon) has a different calling convention from x86-64 that affects how small structs and floating-point aggregates are passed.
| Feature | x86-64 (System V) | ARM64 (Apple AAPCS) | Detected by abicheck? |
|---|---|---|---|
| Small struct (≤16 B) | Stack or reg pair | Passed in GP registers | ✅ TYPE_SIZE_CHANGED catches size delta |
| HFA (Homogeneous Floating-point Aggregate ≤4 floats) | Stack | SIMD/FP registers | ⚠️ Size same, registers differ — NOT detected |
| HVA (Homogeneous Vector Aggregate) | Stack | SIMD/FP registers | ⚠️ Size same, registers differ — NOT detected |
| Return in registers | RDX:RAX (x86-64) | x0:x1 (ARM64) | ⚠️ Not tracked (no calling-convention change kind) |
Tracked: abicc issues #116 (small-struct register passing) · #119 (install_name).
install_name tracking (#119)¶
install_name (LC_ID_DYLIB) is the macOS equivalent of ELF SONAME.
abicheck now tracks this — a change emits SONAME_CHANGED with symbol="LC_ID_DYLIB".
| Scenario | Status |
|---|---|
| install_name changes between versions | ✅ SONAME_CHANGED emitted |
| install_name absent → set | ✅ tracked |
| No change | ✅ no false positive |
Support claim¶
ARM64/macOS: Experimental
- Symbol diff: fully supported (export table via macholib)
- Type/param diff: requires Xcode clang + castxml (≥ 0.9.0 with Apple toolchain backend)
- HFA/HVA calling-convention drift: not directly detected — workaround: always check TYPE_SIZE_CHANGED on structs