Skip to content

CI

CI #678

Workflow file for this run

name: CI
on:
push:
pull_request:
schedule:
- cron: 00 4 * * *
env:
CARGO_TERM_COLOR: always
permissions: {}
jobs:
llvm:
uses: ./.github/workflows/llvm.yml
lint-stable:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
components: clippy, rust-src
- name: Run clippy
run: cargo clippy --features llvm-21,no-llvm-linking --all-targets --workspace -- --deny warnings
lint-nightly:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly
components: rustfmt, rust-src
- name: Check formatting
run: cargo fmt --all -- --check
build:
runs-on: ${{ matrix.platform.os }}
# We work with two git repositories in this workflow:
#
# - bpf-linker
# - aya (for integration tests)
#
# Cargo searches for `.cargo` directories recursively in all parent
# directories. Therefore, nesting different Rust projects with their own
# `.cargo/config.toml` files in the same hierarchy (one nested in another)
# causes cargo to read and merge both configurations.
#
# To avoid that, we clone both repositories in separate directories inside
# the workspace.
defaults:
run:
working-directory: bpf-linker
strategy:
fail-fast: false
matrix:
toolchain:
- rust: 1.90.0
llvm: 20
exclude-features: default,llvm-19,llvm-21,rust-llvm-19,rust-llvm-21
- rust: stable
llvm: 21
exclude-features: default,llvm-19,llvm-20,rust-llvm-19,rust-llvm-20
- rust: beta
llvm: 21
exclude-features: default,llvm-20,rust-llvm-20
- rust: nightly
llvm: 21
exclude-features: llvm-20,rust-llvm-20
platform:
# Rust CI ships only one flavor of libLLVM, dynamic or static, per
# target. Linux GNU targets come with dynamic ones. Apple and Linux
# musl targets come with static ones.
- os: macos-latest
static-target: aarch64-apple-darwin
- os: macos-15-intel
static-target: x86_64-apple-darwin
# We don't use ubuntu-latest because we care about the apt packages available.
- os: ubuntu-22.04
dynamic-target: x86_64-unknown-linux-gnu
static-target: x86_64-unknown-linux-musl
- os: ubuntu-22.04-arm
dynamic-target: aarch64-unknown-linux-gnu
static-target: aarch64-unknown-linux-musl
llvm-from:
- packages
- rust-ci
include:
# Currently we build LLVM from source only for Linux x86_64.
- toolchain:
rust: nightly
llvm: 21
exclude-features: llvm-20,rust-llvm-20
platform:
os: ubuntu-22.04
llvm-from: source
name: os=${{ matrix.platform.os }} rustc=${{ matrix.toolchain.rust }} llvm-version=${{ matrix.toolchain.llvm }} llvm-from=${{ matrix.llvm-from }}
needs: llvm
env:
RUST_BACKTRACE: full
# Features that have to be included for dynamic linking.
LLVM_FEATURES_DYNAMIC: llvm-${{ matrix.toolchain.llvm }}
# Features that have to be included for static linking.
LLVM_FEATURES_STATIC: llvm-${{ matrix.toolchain.llvm }},llvm-link-static
# Features that have to be excluded when running `cargo hack --feature-powerset`
# and intending to link dynamically.
LLVM_EXCLUDE_FEATURES_DYNAMIC: llvm-link-static,no-llvm-linking
RUSTC_LLVM_INSTALL_DIR_DYNAMIC: /tmp/rustc-llvm-dynamic
RUSTC_LLVM_INSTALL_DIR_STATIC: /tmp/rustc-llvm-static
steps:
- uses: actions/checkout@v6
with:
path: bpf-linker
- name: Install Rust ${{ matrix.toolchain.rust }}
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.toolchain.rust }}
components: rust-src
- name: Check (default features, no system LLVM)
run: cargo check
- name: Build (default features, no system LLVM)
run: cargo build
- name: Install btfdump
run: cargo install btfdump
- name: Add clang to PATH
if: runner.os == 'Linux'
# ubuntu-22.04 comes with clang 13-15[0]; support for signed and 64bit
# enum values was added in clang 15[1] which isn't in `$PATH`.
#
# [0] https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2204-Readme.md
#
# [1] https://github.com/llvm/llvm-project/commit/dc1c43d
run: echo /usr/lib/llvm-15/bin >> $GITHUB_PATH
- name: Install LLVM (Linux, packages)
if: matrix.llvm-from == 'packages' && runner.os == 'Linux'
run: |
set -euxo pipefail
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
echo -e deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-${{ matrix.toolchain.llvm }} main | sudo tee /etc/apt/sources.list.d/llvm.list
sudo apt update
sudo apt -y install llvm-${{ matrix.toolchain.llvm }}-dev
echo /usr/lib/llvm-${{ matrix.toolchain.llvm }}/bin >> $GITHUB_PATH
- name: Install LLVM (macOS, packages)
if: matrix.llvm-from == 'packages' && runner.os == 'macOS'
run: |
set -euxo pipefail
brew install llvm@${{ matrix.toolchain.llvm }}
echo $(brew --prefix llvm@${{ matrix.toolchain.llvm }})/bin >> $GITHUB_PATH
# DYLD_LIBRARY_PATH is needed because we're going to link everything dynamically below. This
# doesn't affect behavior, but greatly reduces disk usage.
echo "DYLD_LIBRARY_PATH=$(brew --prefix llvm@${{ matrix.toolchain.llvm }})/lib" >> $GITHUB_ENV
- name: Install LLVM from Rust CI
if: matrix.llvm-from == 'rust-ci'
run: |
set -euxo pipefail
mkdir -p $RUSTC_LLVM_INSTALL_DIR_DYNAMIC $RUSTC_LLVM_INSTALL_DIR_STATIC
rustc_sha=$(cargo xtask rustc-llvm-commit --github-token "${{ secrets.GITHUB_TOKEN }}")
download_llvm() {
local target=$1
local install_dir=$2
wget -q -O - "https://ci-artifacts.rust-lang.org/rustc-builds/$rustc_sha/rust-dev-nightly-$target.tar.xz" | \
tar -xJ --strip-components 2 -C $install_dir
}
if [[ -n "${{ matrix.platform['dynamic-target'] }}" ]]; then
download_llvm \
"${{ matrix.platform['dynamic-target'] }}" \
${RUSTC_LLVM_INSTALL_DIR_DYNAMIC}
# LD_LIBRARY_PATH is needed because we're going to link everything dynamically below. This
# doesn't affect behavior, but greatly reduces disk usage.
echo "LD_LIBRARY_PATH=${RUSTC_LLVM_INSTALL_DIR_DYNAMIC}/lib" >> $GITHUB_ENV
# We start with steps that use dynamic linking. Add llvm-config
# associated with dynamic target to `PATH`.
echo "${RUSTC_LLVM_INSTALL_DIR_DYNAMIC}/bin" >> $GITHUB_PATH
fi
if [[ -n "${{ matrix.platform['static-target'] }}" ]]; then
download_llvm \
"${{ matrix.platform['static-target'] }}" \
${RUSTC_LLVM_INSTALL_DIR_STATIC}
if [[ "${{ runner.os }}" == "Linux" ]]; then
# `FileCheck` binary shipped in musl tarballs is linked dynamically
# to musl, we can't execute it on Ubuntu.
rm -f "${RUSTC_LLVM_INSTALL_DIR_STATIC}/bin/FileCheck"
fi
fi
- name: Restore LLVM from GitHub Actions
if: matrix.llvm-from == 'source'
uses: actions/cache/restore@v4
with:
path: llvm-install
key: ${{ needs.llvm.outputs.cache-key }}
fail-on-cache-miss: true
- name: Add LLVM to PATH && LD_LIBRARY_PATH
if: matrix.llvm-from == 'source'
run: |
set -euxo pipefail
echo "${{ github.workspace }}/llvm-install/bin" >> $GITHUB_PATH
# LD_LIBRARY_PATH is needed because we're going to link everything dynamically below. This
# doesn't affect behavior, but greatly reduces disk usage.
echo "LD_LIBRARY_PATH=${{ github.workspace }}/llvm-install/lib" >> $GITHUB_ENV
# llvm-sys discovers link flags at build script time; these are cached by cargo. The cached
# flags may be incorrect when the cache is reused across LLVM versions.
- name: Bust llvm-sys cache
run: |
set -euxo pipefail
cargo clean -p llvm-sys
cargo clean -p llvm-sys --release
- uses: taiki-e/install-action@cargo-hack
- name: Check (dynamic linking, feature powerset)
if: matrix.platform.dynamic-target || matrix.llvm-from != 'rust-ci'
run: |
cargo hack check --feature-powerset --exclude-features \
${{ env.LLVM_EXCLUDE_FEATURES_DYNAMIC }},${{ matrix.toolchain.exclude-features }} \
--features ${{ env.LLVM_FEATURES_DYNAMIC }}
- name: Build (dynamic linking, feature powerset)
if: matrix.platform.dynamic-target || matrix.llvm-from != 'rust-ci'
run: |
cargo hack build --feature-powerset --exclude-features \
${{ env.LLVM_EXCLUDE_FEATURES_DYNAMIC }},${{ matrix.toolchain.exclude-features }} \
--features ${{ env.LLVM_FEATURES_DYNAMIC }}
# Toolchains provided by rustup include standard library artifacts
# only for Tier 1 targets, which do not include BPF targets.
#
# The default workaround is to use the `rustc-build-sysroot` crate to
# build a custom sysroot with the required BPF standard library before
# running compiler tests.
#
# `RUSTC_BOOTSTRAP` is needed to use `rustc-build-sysroot` on stable Rust.
- name: Test (sysroot built on demand, dynamic linking)
if: matrix.platform.dynamic-target || matrix.llvm-from != 'rust-ci'
run: |
RUSTC_BOOTSTRAP=1 cargo hack test --feature-powerset \
--exclude-features \
${{ env.LLVM_EXCLUDE_FEATURES_DYNAMIC }},${{ matrix.toolchain.exclude-features }} \
--features ${{ env.LLVM_FEATURES_DYNAMIC }}
# To make things easier for package maintainers, the step of building a
# custom sysroot can be skipped by setting the `BPFEL_SYSROOT_DIR`
# environment variable to the path of the prebuilt BPF sysroot.
#
# Test this configuration by prebuilding the BPF standard library
# manually.
#
# `RUSTC_BOOTSTRAP` is needed to make `xtask build-std` work on stable
# Rust.
- name: Build BPF standard library
run: |
set -euxo pipefail
RUSTC_SRC="$(rustc --print sysroot)/lib/rustlib/src/rust/library"
BPFEL_SYSROOT_DIR="${{ github.workspace }}/bpf-sysroot"
RUSTC_BOOTSTRAP=1 cargo xtask build-std \
--rustc-src "$RUSTC_SRC" \
--sysroot-dir "$BPFEL_SYSROOT_DIR" \
--target bpfel-unknown-none
- name: Test (prebuilt BPF standard libary, dynamic linking)
if: matrix.platform.dynamic-target || matrix.llvm-from != 'rust-ci'
run: |
BPFEL_SYSROOT_DIR="${{ github.workspace }}/bpf-sysroot" \
cargo hack test --feature-powerset --exclude-features \
${{ env.LLVM_EXCLUDE_FEATURES_DYNAMIC }},${{ matrix.toolchain.exclude-features }} \
--features ${{ env.LLVM_FEATURES_DYNAMIC }}
- uses: actions/checkout@v6
if: runner.os == 'Linux' && matrix.toolchain.rust == 'nightly'
with:
repository: aya-rs/aya
path: aya
submodules: recursive
- name: Install
if: runner.os == 'Linux' && matrix.toolchain.rust == 'nightly'
run: |
cargo install --path . --no-default-features --features \
${{ env.LLVM_FEATURES_DYNAMIC }}
- name: Run aya integration tests
if: runner.os == 'Linux' && matrix.toolchain.rust == 'nightly'
working-directory: aya
run: cargo xtask integration-test local
- name: Prepare for static linking (LLVM from Rust CI)
if: matrix.llvm-from == 'rust-ci'
run: |
echo "${RUSTC_LLVM_INSTALL_DIR_STATIC}/bin" >> $GITHUB_PATH
- name: Install static libraries (macOS)
if: runner.os == 'macOS'
# macOS does not provide any static libraries. Homebrew does provide
# them, but in custom paths that the system-wide clang is not aware of.
# Point build.rs to them by setting environment variables.
#
# We install llvm package only for libc++.
#
# libLLVM from homebrew requires zstd.
run: |
set -euxo pipefail
brew install llvm zlib
echo "CXXSTDLIB_PATH=$(brew --prefix llvm)/lib/c++" >> $GITHUB_ENV
echo "ZLIB_PATH=$(brew --prefix zlib)/lib" >> $GITHUB_ENV
if [[ "${{ matrix.llvm-from }}" == "packages" ]]; then
brew install zstd
echo "LIBZSTD_PATH=$(brew --prefix zstd)/lib" >> $GITHUB_ENV
fi
- name: Check (static linking, single feature set)
# Static linking in combination with `cargo hack --feature-powerset`
# (multiple builds) increases the disk usage massively. Therefore we
# perform all static builds with only one fixed feature set.
run: |
cargo check --no-default-features --features \
${{ env.LLVM_FEATURES_STATIC }}
- name: Build (static linking, single feature set)
run: |
cargo build --no-default-features --features \
${{ env.LLVM_FEATURES_STATIC }}
- name: Test (sysroot built on demand, static linking)
run: |
RUSTC_BOOTSTRAP=1 cargo test --no-default-features --features \
${{ env.LLVM_FEATURES_STATIC }}
- name: Test (prebuilt BPF standard library, static linking)
run: |
BPFEL_SYSROOT_DIR="${{ github.workspace }}/bpf-sysroot" \
cargo test --no-default-features --features \
${{ env.LLVM_FEATURES_STATIC }}
- name: Report disk usage
if: ${{ always() }}
uses: ./bpf-linker/.github/actions/report-disk-usage