Compile Linux kernels to LLVM bitcode and kernel images with one stable command.
llbic is a Linux kernel build CLI for researchers, tool builders, and agent
workflows that need reproducible kernel artifacts instead of ad hoc scripts. It
pairs an explicit staged command model with a stable machine-readable manifest
so builds are easy to automate, inspect, and reuse.
llbic now supports Rust-enabled Linux kernel builds for kernel families with
published Rust LLVM toolchains on kernel.org (6.19, 6.18, 6.17, 6.12,
6.6, 6.1), including scoped Rust sample targets such as
samples/rust/rust_print.o. Rust mode uses the matching LLVM toolchain set for
the selected kernel family so the emitted C and Rust bitcode can be inspected
with one coherent LLVM toolchain.
./llbic build 6.18.16 --out-of-tree --jsonThat single command:
- Downloads the requested kernel tarball from
kernel.org - Extracts the source into
sources/linux-6.18.16 - Compiles the kernel with the selected backend and toolchain
- Writes logs, a machine-readable manifest, and the bitcode list under
out/linux-6.18.16-x86_64-clang18/ - Prints the same build summary to stdout because
--jsonwas requested
You run ./llbic from the repository root. The CLI creates and manages
sources/ and out/ automatically, so you do not need to prepare build
directories by hand.
Expected output layout:
out/linux-6.18.16-x86_64-clang18/
llbic.log
kernel-build.log
llbic.json
bitcode_files.txt
./llbic inspect out/linux-6.18.16-x86_64-clang18/llbic.json --jsonUse inspect to read back the manifest from a completed build without
rerunning any build steps. This is useful in scripts and agent workflows when
you want to verify the recorded kernel version, architecture, artifact paths,
and bitcode summary from out/linux-6.18.16-x86_64-clang18/llbic.json. Stable path fields are
workspace-relative, even when ./llbic runs inside Docker. Use the runtime
and paths blocks when you need the local container or host resolution.
Example response shape (abridged):
{
"status": "success",
"exit_code": 0,
"error_step": null,
"error": null,
"kernel_version": "6.18.16",
"kernel_name": "linux-6.18.16",
"source_url": "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.18.16.tar.xz",
"source_dir": "sources/linux-6.18.16",
"output_dir": "out/linux-6.18.16-x86_64-clang18",
"log_file": "out/linux-6.18.16-x86_64-clang18/llbic.log",
"strategy": "lto",
"kernel_build_log": "out/linux-6.18.16-x86_64-clang18/kernel-build.log",
"arch": "x86_64",
"arch_is_default": 1,
"cross_compile": null,
"cross_compile_is_default": 1,
"defconfig": "defconfig",
"defconfig_is_default": 1,
"build_layout": "outtree",
"build_layout_is_default": 0,
"scope": "full",
"requested_files": [],
"make_targets": [],
"kconfig_fragments": [],
"kconfig_fragments_count": 0,
"requested_clang": "18",
"kbuild_dir": "out/linux-6.18.16-x86_64-clang18/kbuild-x86_64-clang18",
"config_path": "out/linux-6.18.16-x86_64-clang18/kbuild-x86_64-clang18/.config",
"config_sha256": "<sha256>",
"bitcode_root": "out/linux-6.18.16-x86_64-clang18/kbuild-x86_64-clang18",
"bitcode_list_file": "out/linux-6.18.16-x86_64-clang18/bitcode_files.txt",
"clang": "clang-18",
"llvm_major": "18",
"runtime": {
"execution": "host",
"workspace_root": "<workspace-root>",
"sources_root": "<sources-root>",
"output_root": "<output-root>"
},
"paths": {
"source_dir": {
"portable": "sources/linux-6.18.16",
"runtime_path": "<runtime-specific>",
"resolved_path": "<host-specific>"
}
},
"bitcode_files": [
"out/linux-6.18.16-x86_64-clang18/kbuild-x86_64-clang18/kernel/sched/core.bc"
],
"bitcode_files_rel": [
"kernel/sched/core.bc"
],
"bitcode_count": 1,
"vmlinux_bc": null,
"kernel_images": [
"vmlinux",
"arch/x86/boot/bzImage"
],
"kernel_images_abs": [
"out/linux-6.18.16-x86_64-clang18/kbuild-x86_64-clang18/vmlinux",
"out/linux-6.18.16-x86_64-clang18/kbuild-x86_64-clang18/arch/x86/boot/bzImage"
]
}The public command tree is:
llbic build <version>
llbic download [version|url ...]
llbic extract
llbic compile [kernel-name]
llbic inspect <output-dir|llbic.json>
llbic clean [build|sources|all]
Use build when you want the full workflow in one command:
./llbic build 6.18.16 --arch arm64 --out-of-treeUse --rust when you want llbic to enable Rust support, Rust samples, and
the Rust sample configs automatically. The current Rust path is intentionally
gated to kernel families with published Rust LLVM toolchains on kernel.org:
6.19, 6.18, 6.17, 6.12, 6.6, and 6.1.
In Rust mode, llbic selects the matching LLVM+Rust toolchain for the kernel
family automatically. --clang is not accepted together with --rust.
./llbic build 6.19.7 --rust --out-of-tree --jsonUse scoped compilation to build only selected translation units for debugging, verification, or targeted bitcode generation:
./llbic build 6.18.16 --out-of-tree --file kernel/sched/core.c --jsonUse download when you only want to fetch kernel archives:
./llbic download 6.18.16 --json
./llbic download https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.18.16.tar.xz --jsonUse extract when archives already exist locally and you want unpacked source trees:
./llbic extract --jsonUse compile when the extracted linux-* tree already exists and you do not
want to re-download or re-extract. compile reuses the same build pipeline and
artifact contract as build; it just requires the source tree to already be
present:
./llbic compile linux-6.18.16 --jsonUse inspect to summarize an existing build without rerunning it:
./llbic inspect ./out/linux-6.18.16-x86_64-clang18/llbic.json --jsonUse clean to remove generated artifacts:
./llbic clean build --json
./llbic clean sources --json
./llbic clean all --jsonFlags let you shape the build itself: target architecture, toolchain version, config source, build layout, output identity, and whether the result should be human-readable or machine-readable.
Flags:
--arch, -a:x86_64(default),arm,arm64,mips,riscv--clang: select the LLVM/Clang major version for non-Rust builds--cross:CROSS_COMPILEprefix (defaults are applied for some arches; override as needed)--defconfig: kbuild config target (default:defconfig)--kconfig, -K: merge one or more Kconfig fragments into the generated.config(repeatable)--file, -f: compile only selected source-relative translation units--rust: enable Rust support,SAMPLES,SAMPLES_RUST, and the Rust sample configs automatically for supported kernel families (6.19,6.18,6.17,6.12,6.6,6.1);llbicselects the matching LLVM+Rust toolchain automatically--output, -o: write the build to an explicit output directory; otherwisellbicusesout/linux-<version>-<arch>-clang<version>/--json: print a structured status or manifest to stdout--verbose, -V: passV=1to the kernel build--outtree,--out-of-tree: usemake O=<dir>for an out-of-tree build--intree: build in the source tree and runmake cleanfirst
Example: build ARM64 defconfig plus your own config fragment:
./llbic build 6.18.16 --arch arm64 --out-of-tree -K ./my-kconfig.fragmentEnvironment variables control how llbic runs the build backend. They are
runtime overrides, not build-definition flags. llbic now uses the prepared
host toolchain by default. Set LLBIC_BACKEND=docker when you want the
containerized toolchain path, and use LLBIC_REBUILD=1 to force rebuilding the
selected Docker image.
For host Rust builds, llbic can prepare the required Rust toolchain
automatically via scripts/install_rust_env.sh when the selected version is
missing. You can also run it manually:
bash scripts/install_rust_env.sh --toolchain 1.93.0The Docker images use the same installer in system mode, so the host and container Rust paths stay aligned.
build always writes llbic.json, even on failure. --json additionally
emits structured output to stdout. Staged commands such as download,
extract, compile, inspect, and clean use --json for their stdout
response.
Artifacts are written under out/linux-<version>-<arch>-clang<version>/ by default (override with
--output):
llbic.log: end-to-end build logkernel-build.log: raw kernel build output from the underlyingmakestepsbitcode_files.txt: list of detected LLVM bitcode files (relative paths underbitcode_root)llbic.json: machine-readable build summary
The build manifest includes these top-level fields:
statusexit_codeerror_steperrorkernel_versionkernel_namesource_urlsource_diroutput_dirlog_filestrategyarcharch_is_defaultcross_compilecross_compile_is_defaultdefconfigdefconfig_is_defaultbuild_layoutbuild_layout_is_defaultscoperequested_filesmake_targetskconfig_fragmentskconfig_fragments_countrequested_clangkbuild_dirbitcode_rootkernel_build_logbitcode_list_filebitcode_filesbitcode_files_relbitcode_countconfig_pathconfig_sha256clangllvm_majorkernel_imageskernel_images_absvmlinux_bc
Treat the portable scalar path fields such as source_dir, output_dir,
bitcode_root, kernel_build_log, and bitcode_list_file as the stable
artifact identities.
Note: kernel/time/timeconst.bc in the Linux source tree is an input for the bc
calculator (used to generate include/generated/timeconst.h), not LLVM bitcode.
The README reflects build status through generated files under status/, not
through hand-edited prose.
The flow is:
llbicwrites onellbic.jsonmanifest per build underout/python3 scripts/collect_status.pyreads the completed manifests- the collector rewrites the committed status artifacts and badge payloads
- the README links to those generated outputs
In practice, that means the README status can be refreshed automatically after new build results are collected. You do not edit the status summary by hand; you regenerate it from the manifests.
The generated outputs are:
status/status.json: machine-readable support rowsstatus/STATUS.md: rendered support tablestatus/badges/overall.json: overall pass/fail badge payloadstatus/badges/bitcode.json: bitcode-emission badge payloadstatus/badges/vmlinux.json:vmlinuxbuild badge payload
Refresh the status artifacts with:
python3 scripts/collect_status.pyPrint the current badge summary locally with:
python3 scripts/collect_status.py --print-badgesThe board is derived from completed out/**/llbic.json manifests and tracked
by arch + requested_clang + kernel, so the same kernel and architecture built
under different Clang versions remain distinguishable.
The status board follows llbic's active backend selection. Use the prepared
host toolchain when available, or set LLBIC_BACKEND=docker when you want the
containerized path and the image-defined toolchain selection.
| Image | Kernels | Clang |
|---|---|---|
ghcr.io/cyruscyliu/llbic:latest |
6.x, 7.x | 14, 15, 16, 18 |
ghcr.io/cyruscyliu/llbic:mid |
4.x, 5.x | 8, 9, 10, 11, 12 |
ghcr.io/cyruscyliu/llbic:legacy |
2.6, 3.x | 6.0, 7, 8 |
Contributions are welcome through issues and pull requests.
If a change affects CLI behavior, backend selection, manifests, artifacts,
status workflow, or agent guidance, update README.md.
See LICENSE.