CBake (cross-bake) is a lightweight toolkit for building and using cross-compilation environments. It combines Docker-built Linux sysroots, CMake toolchain files, PowerShell helpers, and LLVM/Clang so projects can target Linux distributions and common mobile or desktop platforms from a consistent workflow.
| Area | Contents |
|---|---|
| Linux sysroots | Docker recipes for Ubuntu, Debian, RHEL, and Alpine, plus PowerShell commands to package and import sysroots |
| CMake toolchains | Entry points for Linux, Android, iOS, and Windows targets |
| Cargo support | CMake logic that generates Cargo environment files for Rust cross-compilation with the active CMake toolchain |
| Automation | GitHub Actions workflows for building sysroot artifacts and publishing release assets |
.
|-- build.ps1 # CLI wrapper for CBake commands
|-- cbake.psm1 # PowerShell module with sysroot helpers
|-- cargo/ # Cargo environment generation for CMake builds
|-- cmake/ # Cross-compilation toolchain files
|-- packages/ # Generated sysroot archives, ignored by git
|-- recipes/ # Docker build recipes for Linux sysroots
`-- sysroots/ # Imported sysroots, ignored by git
Install the tools for the workflows you plan to use:
| Workflow | Required tools |
|---|---|
| All CBake commands | PowerShell 7 |
| Linux sysroot builds | Docker with buildx, QEMU/binfmt for non-native architectures, tar, and xz |
| C/C++ cross-compilation | CMake, Ninja, and LLVM/Clang with llvm-config on PATH |
| Android targets | Android NDK and ANDROID_NDK pointing to the NDK root |
| iOS targets | Xcode command-line tools on macOS |
| Windows targets | MSVC/Windows SDK on Windows, or the provided clang-cl/MSVC wrapper flow on other hosts |
| Tests | Pester 5 for the PowerShell test suite |
Sysroot creation should run on a Linux filesystem. On Windows, use WSL2 for the Docker build and packaging steps.
Clone the repository and import the PowerShell module:
$Env:CBAKE_HOME = (Get-Location).Path
Import-Module (Join-Path $Env:CBAKE_HOME 'cbake.psm1') -Force
Get-CBakePathBuild and import a Linux sysroot:
New-CBakeSysroot -Distro 'ubuntu-24.04' -Arch 'arm64'
Import-CBakeSysroot -Distro 'ubuntu-24.04' -Arch 'arm64'The packaged archive is written to packages\ubuntu-24.04-arm64-sysroot.tar.xz, and the imported sysroot is expanded under sysroots\ubuntu-24.04-arm64.
You can also use the command wrapper:
.\build.ps1 sysroot -Distro 'ubuntu-24.04' -Arch 'arm64'The GitHub Actions matrix builds every recipe for amd64 and arm64. It also builds the fixed ARMv7 compatibility baselines below with the arm label. arm is intentionally aligned with the linux-arm and linux-musl-arm runtime identifiers; CBake maps it to Docker buildx platform linux/arm/v7.
| Family | Recipes |
|---|---|
| Ubuntu | ubuntu-18.04, ubuntu-20.04, ubuntu-22.04, ubuntu-24.04 |
| Debian | debian-10, debian-11, debian-12 |
| RHEL | rhel8, rhel9 |
| Alpine | alpine-3.17, alpine-3.21 |
| Compatibility baseline | Archive | Imported sysroot | GCC and Clang target | GCC target directory |
|---|---|---|---|---|
| Ubuntu 18.04 (glibc) | ubuntu-18.04-arm-sysroot.tar.xz |
sysroots\ubuntu-18.04-arm |
arm-linux-gnueabihf |
usr\lib\gcc\arm-linux-gnueabihf\<gcc-version> |
| Alpine 3.17 (musl) | alpine-3.17-arm-sysroot.tar.xz |
sysroots\alpine-3.17-arm |
armv7-alpine-linux-musleabihf |
usr\lib\gcc\armv7-alpine-linux-musleabihf\<gcc-version> |
Import either archive with Import-CBakeSysroot -Distro '<distro-version>' -Arch 'arm'. Set SYSROOT_NAME to the imported directory name (for example, ubuntu-18.04-arm). The Linux toolchain finds the target triple from its usr\lib\gcc\<target>\<gcc-version> layout and applies -march=armv7-a for this architecture.
To add a distribution, create a new directory under recipes\ with a Dockerfile and update the workflow matrix if CI should build it.
After importing a sysroot, configure your project with CBake's Linux toolchain:
$ToolchainFile = Join-Path (Join-Path $Env:CBAKE_HOME 'cmake') 'linux.toolchain.cmake'
cmake -S . -B build\ubuntu-24.04-arm64 -G Ninja `
-DCMAKE_TOOLCHAIN_FILE="$ToolchainFile" `
-DSYSROOT_NAME='ubuntu-24.04-arm64' `
-DCMAKE_BUILD_TYPE=Release
cmake --build build\ubuntu-24.04-arm64SYSROOT_NAME selects a directory under sysroots\. CBake infers the target architecture from the sysroot name and configures Clang, LLD, libgcc, libstdc++, and pkg-config paths from the imported sysroot.
With CMake 3.21 or newer, you can also set the CMAKE_TOOLCHAIN_FILE environment variable instead of passing -DCMAKE_TOOLCHAIN_FILE every time.
Use the target-specific files in cmake\ when building for non-Linux platforms:
| Platform | Toolchain entry points |
|---|---|
| Android | android-arm.toolchain.cmake, android-arm64.toolchain.cmake, android-x86.toolchain.cmake, android-x86_64.toolchain.cmake |
| iOS | ios-arm.toolchain.cmake, ios-arm64.toolchain.cmake, ios-armv7.toolchain.cmake, ios-x86_64.toolchain.cmake |
| Linux | linux-amd64.toolchain.cmake, linux-arm.toolchain.cmake, linux-arm64.toolchain.cmake, linux.toolchain.cmake |
| Windows | windows-x86.toolchain.cmake, windows-x64.toolchain.cmake, windows-arm64.toolchain.cmake |
Example:
$ToolchainFile = Join-Path (Join-Path $Env:CBAKE_HOME 'cmake') 'android-arm64.toolchain.cmake'
cmake -S . -B build\android-arm64 -G Ninja -DCMAKE_TOOLCHAIN_FILE="$ToolchainFile"
cmake --build build\android-arm64The cargo\CMakeLists.txt helper emits Cargo-compatible environment files under $CARGO_HOME\cbake for the active CMake target. It prepares linker, cc-rs, pkg-config-rs, and cmake-rs variables so Rust crates can reuse the same sysroot and compiler settings as CMake.
Generated files include:
| File | Purpose |
|---|---|
<target>.env |
dotenv-compatible environment variables |
<target>-enter.sh / <target>-leave.sh |
shell scripts to enter and leave the Cargo environment |
<target>-enter.ps1 / <target>-leave.ps1 |
PowerShell scripts to enter and leave the Cargo environment |
Set CARGO_CBAKE_DIR or CARGO_CBAKE_NAME during CMake configuration to customize where these files are written and how they are named.
CBake resolves paths through environment variables, falling back to folders inside this repository:
| Variable | Default |
|---|---|
CBAKE_HOME |
repository root |
CBAKE_CMAKE_DIR |
CBAKE_HOME\cmake |
CBAKE_SYSROOTS_DIR |
CBAKE_HOME\sysroots |
CBAKE_PACKAGES_DIR |
CBAKE_HOME\packages |
CBAKE_RECIPES_DIR |
CBAKE_HOME\recipes |
Use these overrides when sysroot archives or imported sysroots need to live outside the checkout.
Run the focused checks before submitting PowerShell or workflow changes:
pwsh -NoLogo -NoProfile -Command "Import-Module .\cbake.psm1 -Force; Get-CBakePath"
pwsh -NoLogo -NoProfile -Command "Invoke-Pester -Path .\tests -CI"The Pester tests mock Docker and tar interactions, so they do not build sysroots or require Docker to be running.
cbake sysroots is a manually dispatched workflow that builds every distro and architecture combination in the recipe matrix and uploads each sysroot archive as an artifact.
cbake release is a manually dispatched workflow that downloads artifacts from a successful sysroot workflow run, writes SHA-256 checksums, and publishes a GitHub release. If no version is supplied, it uses a date-based version in the form yyyy.MM.dd.0.
| Symptom | Check |
|---|---|
SYSROOT_NAME not defined |
Pass -DSYSROOT_NAME='<distro>-<version>-<arch>' or set the SYSROOT_NAME environment variable. |
CMAKE_SYSROOT directory does not exist |
Run Import-CBakeSysroot for the selected sysroot or point CMAKE_SYSROOT at an existing imported sysroot. |
LLVM prefix could not be found |
Install LLVM/Clang and ensure llvm-config is on PATH, or pass -DLLVM_PREFIX=<path>. |
Android configure fails with ANDROID_NDK is not set |
Set ANDROID_NDK to the Android NDK root before running CMake. |
Docker buildx fails for arm64 on an amd64 host |
Install and enable QEMU/binfmt support before building non-native images. |
CBake is distributed under the MIT license. See LICENSE.