Build System and CI

Relevant source files

This document covers the automated build system and continuous integration (CI) pipeline for the kernel_guard crate. The CI system is implemented using GitHub Actions and provides multi-architecture testing, code quality enforcement, and automated documentation deployment.

For information about setting up a local development environment, see Development Environment. For details about the specific architectures supported, see Multi-Architecture Support.

CI Pipeline Overview

The kernel_guard project uses GitHub Actions for continuous integration, defined in a single workflow file that handles both build/test operations and documentation deployment. The pipeline is triggered on all push and pull request events.

CI Pipeline Structure

flowchart TD
TRIGGER["on: [push, pull_request]"]
JOBS["GitHub Actions Jobs"]
CI_JOB["ci job"]
DOC_JOB["doc job"]
MATRIX["strategy.matrix"]
CI_STEPS["CI Steps"]
DOC_PERMISSIONS["permissions: contents: write"]
DOC_STEPS["Documentation Steps"]
TOOLCHAIN["rust-toolchain: [nightly]"]
TARGETS["targets: [5 architectures]"]
CHECKOUT["actions/checkout@v4"]
TOOLCHAIN_SETUP["dtolnay/rust-toolchain@nightly"]
FORMAT_CHECK["cargo fmt --all -- --check"]
CLIPPY_CHECK["cargo clippy"]
BUILD_STEP["cargo build"]
TEST_STEP["cargo test"]
DOC_BUILD["cargo doc --no-deps --all-features"]
PAGES_DEPLOY["JamesIves/github-pages-deploy-action@v4"]

CI_JOB --> CI_STEPS
CI_JOB --> MATRIX
CI_STEPS --> BUILD_STEP
CI_STEPS --> CHECKOUT
CI_STEPS --> CLIPPY_CHECK
CI_STEPS --> FORMAT_CHECK
CI_STEPS --> TEST_STEP
CI_STEPS --> TOOLCHAIN_SETUP
DOC_JOB --> DOC_PERMISSIONS
DOC_JOB --> DOC_STEPS
DOC_STEPS --> DOC_BUILD
DOC_STEPS --> PAGES_DEPLOY
JOBS --> CI_JOB
JOBS --> DOC_JOB
MATRIX --> TARGETS
MATRIX --> TOOLCHAIN
TRIGGER --> JOBS

Sources: .github/workflows/ci.yml(L1 - L56) 

CI Job Configuration

The primary ci job runs on ubuntu-latest and uses a matrix strategy to test multiple configurations simultaneously. The job is configured with fail-fast: false to ensure all matrix combinations are tested even if some fail.

Matrix Strategy

The build matrix tests against multiple target architectures using the nightly Rust toolchain:

Target ArchitecturePurpose
x86_64-unknown-linux-gnuStandard Linux testing and unit tests
x86_64-unknown-noneBare metal x86_64
riscv64gc-unknown-none-elfRISC-V 64-bit bare metal
aarch64-unknown-none-softfloatARM64 bare metal
loongarch64-unknown-none-softfloatLoongArch64 bare metal

Matrix Configuration Flow

flowchart TD
MATRIX_START["strategy.matrix"]
TOOLCHAIN_CONFIG["rust-toolchain: nightly"]
TARGET_CONFIG["targets: 5 architectures"]
NIGHTLY["nightly toolchain"]
X86_LINUX["x86_64-unknown-linux-gnu"]
X86_NONE["x86_64-unknown-none"]
RISCV["riscv64gc-unknown-none-elf"]
AARCH64["aarch64-unknown-none-softfloat"]
LOONG["loongarch64-unknown-none-softfloat"]
COMPONENTS["components: rust-src, clippy, rustfmt"]
TEST_ENABLED["Unit tests enabled"]
BUILD_ONLY["Build only"]

AARCH64 --> BUILD_ONLY
LOONG --> BUILD_ONLY
MATRIX_START --> TARGET_CONFIG
MATRIX_START --> TOOLCHAIN_CONFIG
NIGHTLY --> COMPONENTS
RISCV --> BUILD_ONLY
TARGET_CONFIG --> AARCH64
TARGET_CONFIG --> LOONG
TARGET_CONFIG --> RISCV
TARGET_CONFIG --> X86_LINUX
TARGET_CONFIG --> X86_NONE
TOOLCHAIN_CONFIG --> NIGHTLY
X86_LINUX --> TEST_ENABLED
X86_NONE --> BUILD_ONLY

Sources: .github/workflows/ci.yml(L8 - L12)  .github/workflows/ci.yml(L16 - L19) 

Quality Assurance Steps

The CI job enforces code quality through a series of automated checks:

Quality Assurance Workflow

flowchart TD
SETUP["Rust Toolchain Setup"]
VERSION_CHECK["rustc --version --verbose"]
FORMAT_CHECK["cargo fmt --all -- --check"]
CLIPPY_CHECK["cargo clippy --target TARGET --all-features"]
BUILD_STEP["cargo build --target TARGET --all-features"]
TEST_DECISION["TARGET == x86_64-unknown-linux-gnu?"]
UNIT_TEST["cargo test --target TARGET -- --nocapture"]
COMPLETE["Job Complete"]
CLIPPY_ALLOW["-A clippy::new_without_default"]

BUILD_STEP --> TEST_DECISION
CLIPPY_CHECK --> BUILD_STEP
CLIPPY_CHECK --> CLIPPY_ALLOW
FORMAT_CHECK --> CLIPPY_CHECK
SETUP --> VERSION_CHECK
TEST_DECISION --> COMPLETE
TEST_DECISION --> UNIT_TEST
UNIT_TEST --> COMPLETE
VERSION_CHECK --> FORMAT_CHECK

The clippy step includes a specific allowance for the new_without_default lint, configured via the -A clippy::new_without_default flag.

Sources: .github/workflows/ci.yml(L20 - L30) 

Documentation Job and GitHub Pages

The doc job handles automated documentation generation and deployment to GitHub Pages. This job requires write permissions to the repository contents for deployment.

Documentation Build Process

The documentation job uses specific environment variables and build flags to ensure high-quality documentation:

RUSTDOCFLAGS: -D rustdoc::broken_intra_doc_links -D missing-docs

Documentation Deployment Flow

flowchart TD
DOC_TRIGGER["doc job trigger"]
PERMISSIONS_CHECK["permissions.contents: write"]
ENV_SETUP["RUSTDOCFLAGS environment"]
BRANCH_CHECK["default-branch variable"]
DOC_BUILD["cargo doc --no-deps --all-features"]
INDEX_GEN["Generate index.html redirect"]
BRANCH_CONDITION["github.ref == default-branch?"]
DEPLOY_PAGES["JamesIves/github-pages-deploy-action@v4"]
SKIP_DEPLOY["Skip deployment"]
PAGES_CONFIG["single-commit: truebranch: gh-pagesfolder: target/doc"]
STRICT_DOCS["Broken links fail buildMissing docs fail build"]

BRANCH_CHECK --> DOC_BUILD
BRANCH_CONDITION --> DEPLOY_PAGES
BRANCH_CONDITION --> SKIP_DEPLOY
DEPLOY_PAGES --> PAGES_CONFIG
DOC_BUILD --> INDEX_GEN
DOC_TRIGGER --> PERMISSIONS_CHECK
ENV_SETUP --> BRANCH_CHECK
ENV_SETUP --> STRICT_DOCS
INDEX_GEN --> BRANCH_CONDITION
PERMISSIONS_CHECK --> ENV_SETUP

The index.html generation uses a shell command to extract the crate name and create a redirect:

printf '<meta http-equiv="refresh" content="0;url=%s/index.html">' $(cargo tree | head -1 | cut -d' ' -f1) > target/doc/index.html

Sources: .github/workflows/ci.yml(L32 - L56)  .github/workflows/ci.yml(L40)  .github/workflows/ci.yml(L46 - L48) 

Build and Test Execution

The CI system executes different build and test strategies based on the target architecture:

Target-Specific Behavior

flowchart TD
BUILD_START["cargo build --target TARGET --all-features"]
TARGET_CHECK["Check target architecture"]
LINUX_TARGET["x86_64-unknown-linux-gnu"]
BAREMETAL_X86["x86_64-unknown-none"]
BAREMETAL_RISCV["riscv64gc-unknown-none-elf"]
BAREMETAL_ARM["aarch64-unknown-none-softfloat"]
BAREMETAL_LOONG["loongarch64-unknown-none-softfloat"]
BUILD_SUCCESS["Build Success"]
TEST_CHECK["if: matrix.targets == 'x86_64-unknown-linux-gnu'"]
UNIT_TESTS["cargo test --target TARGET -- --nocapture"]
NO_TESTS["Skip unit tests"]
TEST_COMPLETE["All checks complete"]

BAREMETAL_ARM --> BUILD_SUCCESS
BAREMETAL_LOONG --> BUILD_SUCCESS
BAREMETAL_RISCV --> BUILD_SUCCESS
BAREMETAL_X86 --> BUILD_SUCCESS
BUILD_START --> TARGET_CHECK
BUILD_SUCCESS --> TEST_CHECK
LINUX_TARGET --> BUILD_SUCCESS
NO_TESTS --> TEST_COMPLETE
TARGET_CHECK --> BAREMETAL_ARM
TARGET_CHECK --> BAREMETAL_LOONG
TARGET_CHECK --> BAREMETAL_RISCV
TARGET_CHECK --> BAREMETAL_X86
TARGET_CHECK --> LINUX_TARGET
TEST_CHECK --> NO_TESTS
TEST_CHECK --> UNIT_TESTS
UNIT_TESTS --> TEST_COMPLETE

Unit tests are only executed on the x86_64-unknown-linux-gnu target because the bare metal targets cannot run standard Rust test frameworks.

Sources: .github/workflows/ci.yml(L26 - L30) 

The CI pipeline ensures that the kernel_guard crate builds correctly across all supported architectures while maintaining code quality standards through automated formatting, linting, and testing.