Skip to content

Add ABI checking

Add ABI checking #897

# Copyright 2025 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
name: Build and test C++ Runtime Bindings
on:
push:
branches:
- main
pull_request:
workflow_dispatch:
permissions:
contents: read
# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
cancel-in-progress: true
jobs:
build-cpp-runtime-bindings:
name: Build and unit tests for C++ runtime bindings
runs-on: ubuntu-22.04
strategy:
matrix:
include:
- name: "with static library"
enable_lvq_leanvec: "ON"
require_lto: "ON"
suffix: ""
- name: "public only"
enable_lvq_leanvec: "OFF"
require_lto: "OFF"
suffix: "-public-only"
fail-fast: false
steps:
- uses: actions/checkout@v6
- name: Build Docker image
run: |
docker build -t svs-manylinux228:latest -f docker/x86_64/manylinux228/Dockerfile .
- name: Build libraries in Docker container
run: |
docker run --rm \
-v ${{ github.workspace }}:/workspace \
-w /workspace \
-e ENABLE_LVQ_LEANVEC=${{ matrix.enable_lvq_leanvec }} \
-e REQUIRE_LTO_ARCHIVE=${{ matrix.require_lto }} \
-e SUFFIX=${{ matrix.suffix }} \
svs-manylinux228:latest \
/bin/bash .github/scripts/build-cpp-runtime-bindings.sh
- name: Upload cpp runtime bindings artifacts
uses: actions/upload-artifact@v7
with:
name: svs-cpp-runtime-bindings${{ matrix.suffix }}
path: svs-cpp-runtime-bindings${{ matrix.suffix }}.tar.gz
retention-days: 7 # Reduce retention due to size
- name: Upload conda package artifacts
uses: actions/upload-artifact@v7
with:
name: libsvs-runtime-conda${{ matrix.suffix }}
path: conda-bld/linux-64/libsvs-runtime-*.conda
retention-days: 7
# Run unit tests that were built as part of this job
- name: Run unit tests in Docker container
run: |
docker run --rm \
-v ${{ github.workspace }}:/workspace \
-w /workspace \
-e ENABLE_LVQ_LEANVEC=${{ matrix.enable_lvq_leanvec }} \
svs-manylinux228:latest \
/bin/bash /workspace/.github/scripts/test-cpp-runtime-unit.sh
# Run full test script using the built artifacts
test:
name: Integration tests for C++ runtime
needs: build-cpp-runtime-bindings
runs-on: ubuntu-22.04
strategy:
matrix:
# enable_lvq_leanvec must match the build job's value for this suffix; if they
# disagree, test-faiss.sh expects the wrong outcome from the downloaded artifact.
include:
- name: "with static library"
enable_lvq_leanvec: "ON"
suffix: ""
- name: "public only"
enable_lvq_leanvec: "OFF"
suffix: "-public-only"
fail-fast: false
steps:
- uses: actions/checkout@v6
- name: Build Docker image
run: |
docker build -t svs-manylinux228:latest -f docker/x86_64/manylinux228/Dockerfile .
# Need to download for a new job
- name: Download conda package
uses: actions/download-artifact@v8
with:
name: libsvs-runtime-conda${{ matrix.suffix }}
path: runtime_conda
- name: List available artifacts
run: |
ls -la runtime_conda/
- name: Test in Docker container
run: |
docker run --rm \
-v ${{ github.workspace }}:/workspace \
-v ${{ github.workspace }}/runtime_conda:/runtime_conda \
-w /workspace \
-e ENABLE_LVQ_LEANVEC=${{ matrix.enable_lvq_leanvec }} \
svs-manylinux228:latest \
/bin/bash .github/scripts/test-faiss.sh
# Check the built runtime bindings against the last published release.
#
# Only the default variant is checked: releases publish
# svs-cpp-runtime-bindings.tar.gz but no -public-only asset, so that variant has
# nothing to compare against. It is covered indirectly -- both variants build
# from the same headers.
#
# The comparison primitive is .github/scripts/abi-check.sh, which the
# innersource repo also calls through its submodule path so the two repos cannot
# drift on how the same library is measured.
abi-check:
name: ABI check against the last release
needs: build-cpp-runtime-bindings
runs-on: ubuntu-22.04
# An intentionally-breaking PR still gets a full report: the label downgrades
# this job from blocking to informational rather than skipping it, so the
# break is recorded on the PR instead of going unmeasured.
continue-on-error: ${{ contains(toJson(github.event.pull_request.labels.*.name), '"API/ABI breaking change"') }}
steps:
- uses: actions/checkout@v6
# The hosted ubuntu-22.04 image ships only clang-13/14, which degrades
# abicheck's clang AST frontend to ELF-tier and drops constrained-template
# diffs. innersource gets a c++20-capable clang from its self-hosted
# toolchain; this keeps the two repos measuring at the same fidelity.
- name: Install clang for the AST frontend
run: |
wget -qO /tmp/llvm.sh https://apt.llvm.org/llvm.sh
chmod +x /tmp/llvm.sh
sudo /tmp/llvm.sh 18
sudo apt-get install -y --no-install-recommends libclang-18-dev llvm-18-dev
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-18 100
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-18 100
- name: Install abicheck
run: pip install 'abicheck==0.5.*'
- name: Resolve baseline release tag
id: baseline
env:
GH_TOKEN: ${{ github.token }}
run: |
tag=$(grep -v '^#' .github/abi-baseline-tag | tr -d '[:space:]')
if [ "$tag" = 'latest' ]; then
tag=$(gh release view --json tagName --jq '.tagName')
fi
echo "tag=$tag" >> "$GITHUB_OUTPUT"
# A missing baseline is a hard failure: a green check that silently skipped
# the comparison is worse than a red one.
- name: Download release baseline
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ steps.baseline.outputs.tag }}
run: |
mkdir -p baseline
if ! gh release download "$TAG" --pattern svs-cpp-runtime-bindings.tar.gz \
--dir baseline; then
echo "::error::Release $TAG has no svs-cpp-runtime-bindings.tar.gz asset." \
"Fix the pin in .github/abi-baseline-tag."
exit 1
fi
- name: Download this build
uses: actions/download-artifact@v8
with:
name: svs-cpp-runtime-bindings
path: current
- name: Compare
env:
LIBRARY: libsvs_runtime.so
HEADER_SUBDIR: include/svs/runtime
SUPPRESSIONS: .github/abi-suppressions.yml
POLICY: strict_abi
run: |
chmod +x .github/scripts/abi-check.sh
label='${{ github.event.pull_request.number && format('PR {0}', github.event.pull_request.number) || github.ref_name }}'
rc=0
.github/scripts/abi-check.sh \
'${{ steps.baseline.outputs.tag }}' baseline/svs-cpp-runtime-bindings.tar.gz \
"$label" current/svs-cpp-runtime-bindings.tar.gz || rc=$?
if [ -s abi-report.md ]; then
{
echo "## ABI vs ${{ steps.baseline.outputs.tag }}"
cat abi-report.md
} >> "$GITHUB_STEP_SUMMARY"
fi
# 77 means an input tarball was missing; that is a harness/plumbing
# problem and must fail loudly rather than pass as "no findings".
if [ "$rc" -eq 77 ] || [ "$rc" -eq 64 ]; then
echo "::error::ABI check could not run (rc=$rc)."
exit 1
fi
exit "$rc"