5 releases
Uses new Rust 2024
| new 0.3.2 | Mar 6, 2026 |
|---|---|
| 0.3.1 | Mar 5, 2026 |
| 0.2.1 | Mar 3, 2026 |
| 0.1.2 |
|
#82 in Build Utils
230KB
5K
SLoC
Nishikaze - The West Wind
A CLI companion that orchestrates the whole lifecycle of Zephyr-based projects using a declarative config.
Index
- Why?
- Features
- Installation
- Requirements
- Usage
- Kaze config
- File discovery
- Configuration layers and precedence
- Top-level schema overview
[project][profile.]- Profile selection rules
[build]- Build output layout
[zephyr][project.args]and per-profile args- Arg merge order
[bom]- Minimal config examples
- Verbosity
- Typical workflow
- Sysbuild projects
- SPDX BoM generation
- Workspace management
- Example app
- Similar projects
- License
- Contribution
- Development
- Upcomming features
Why?
Zephyr OS is a dream to work with. Zephyr's west, however, is a different story
(at least for multi image sysbuild projects). Even though at first glance this
meta tool looks exactly like west, you have the option to configure your project
declaratively. I admit, when building a simple Zephyr app, you can just use pure
CMake + ninja/make and configure everything in CMake. However, when building a
multi-image app using sysbuild (e.g. updatehub OTA + mcuboot + app image) then
you're stuck with passing a mile of args into west as you cannot configure it
declaratively and cannot modify CMake config of external modules.
Features
- Manage the whole lifecycle of a Zephyr app - config, build, flash, sim runs
- Supports both simple Zephyr apps and multi-image apps with sysbuild
- Automatic Zephyr workspace detection
- Declarative config through
kaze.toml@ project root - Automatic project dir navigation (can be run from both project root or build dir)
- Automatically detects
sysbuildprojects and adjusts the build accordingly - Supports multiple build profiles (can build multiple binaries for a specific app, useful for simulations or multiple board targets)
- SPDX BoM generation
- Zephyr workspace management
Installation
Install using cargo:
cargo install nishikaze
Requirements
As it's intended to manage Zephyr OS apps, you'll need a workspace setup with Zephyr OS and Zephyr SDK installed.
Usage
Usage: kaze [OPTIONS] <COMMAND>
Commands:
init Initializes project with kaze.toml
boards Lists available boards
runners Lists available runners
profiles Lists profiles configured in kaze.toml
clean Cleans build dir
conf Configure project
build Build binary
run Run simulation
flash Flash binary
menuconfig Run menuconfig
bom Generate SPDX `BoM`
workspace Workspace management
help Print this message or the help of the given subcommand(s)
Options:
-c, --clean Pre-clean the active build dir
-a, --all Run command for all configured profiles (overrides --profile/default)
-p, --profile <PROFILE> Select project profile defined in kaze.toml
-b, --board <BOARD> Zephyr OS board/target (overrides config)
-r, --runner <RUNNER> Zephyr OS flash runner (overrides config)
--project <PROJECT> Explicit project root
-v, --verbose... Verbosity (repeatable)
-d, --dry-run Dry run
-h, --help Print help
-V, --version Print version
Kaze config
kaze.toml is a declarative config located at the project root.
File discovery
kaze locates the project by:
- if
--project <path>is given, use it - else traverse upward from
cwduntilkaze.tomlis found - if run from a build directory, traverse upward to find the owning project root
Configuration layers and precedence
Resolved configuration is produced by merging layers in this order:
- Project config:
<project>/kaze.toml - CLI flags (
--profile,--board,--runner, etc.)
Within the project config:
- global values apply first
- active profile values override global values
- CLI overrides override both
Top-level schema overview
kaze.toml supports these configuration tables:
| Table | Description |
|---|---|
[project] |
Global project configuration |
[build] |
Build layout configuration |
[zephyr] |
Zephyr workspace overrides |
[bom] |
SPDX BoM generation config |
[profile.<name>] |
Build profile |
Recommended top-level tables:
[project]— defaults and profile selection[build]— build directory rules
[project]
| Key | Type | Default | Summary |
|---|---|---|---|
board |
string | (none) | Default Zephyr board |
runner |
string | (none) | Default Zephyr runner |
args |
table | Per-phase args for the profile | |
default_profile |
string | (none) | Default profile name |
name |
string | (optional) | Display name for the project (optional) |
[profile.<name>]
Each profile is a partial override of the global project config.
| Key | Type | Summary |
|---|---|---|
board |
string | Profile board |
runner |
string | Profile runner |
args |
table | Per-phase args for the profile |
Example:
[profile.sim]
board = "native_sim"
[profile.prod]
board = "nucleo_f767zi"
runner = "openocd"
Profile selection rules
When profiles are defined:
- if
--allarg provided -> all profiles selected (kaze runs selected command for all profiles) - else if
default_profiledefined -> selects that profile - else if
--profileprovided -> selects that profile - else -> selects 1st profile defined in config file
When profiles are not defined:
- profile selection is ignored and build is profile-less.
[build]
| Key | Type | Default | Summary |
|---|---|---|---|
root |
string | "build" |
Root build output directory |
link_compile_commands |
bool | true |
When profiles enabled, create root build/compile_commands.json symlink |
Build output layout
- Profile-less layout with no profiles configured:
./<build.root>/ - Profiles layout with profiles configured:
./<build.root>/<profile>/
If building with profiles layout and link_compile_commands=true:
./<build.root>/compile_commands.jsonis a symlink to the selected default/first profile’scompile_commands.jsonIf building a sysbuild project andlink_compile_commands=true:./<build.root>/compile_commands.jsonis a symlink to the project app image'scompile_commands.jsonwhile perserving profile logic. Linking is skipped when building in profile-less layout or whenlink_compile_commands=false.
[zephyr]
| Key | Type | Default | Summary |
|---|---|---|---|
workspace |
string | auto-detect | Zephyr workspace root |
base |
string | ${workspace}/zephyr |
Zephyr base directory |
url |
string | (none) | Zephyr workspace manifest repository url |
manifest |
string | (none) | Zephyr workspace local manifest file path |
Auto-detection order (when not set):
ZEPHYR_BASEenvironment variable- find
.west/by traversing upward; if found, treat its parent as workspace
[project.args] and per-profile args
Args are configurable for phases:
conf(CMake configure)build(Ninja)flash(west flash / runner invocation)run(simulator binary or fallback command)
Value forms:
- string → treated as a single argument string (split behavior is implementation-defined; recommended to use arrays)
- array of strings → preferred, exact args list
Example:
[project.args]
conf = ["-DHG_TEST=ON"]
build = ["-j", "0"]
flash = ["--hex-file", "path/to/other.hex"]
run = ["-flash_mount=seed/sd"]
[profile.sim.args]
run = ["-flash=seed/flash.bin", "-wait_uart"]
Arg merge order
For a given phase:
- global
[project.args.<phase>] - profile
[profile.<name>.args.<phase>] - CLI passthrough args after
--
[bom]
| Key | Type | Default | Summary |
|---|---|---|---|
build |
bool | false |
Enables SPDX BoM generation |
version |
string | "2.2" |
SPDX version ("2.2" / "2.3") |
If BoM generation is enabled, calling kaze bom will configure the project for
BoM generation and generates SPDX BoM.
For sysbuild projects, you have to manually enable CONFIG_BUILD_OUTPUT_META=y
for all sysbuild images in their respective Kconfigs.
Minimal config examples
1) Simple project (profile-less)
[project]
board = "nucleo_f767zi"
runner = "openocd"
2) Project with profiles
[project]
default_profile = "sim"
[profile.sim]
board = "native_sim"
runner = "native"
[profile.prod]
board = "nucleo_f767zi"
runner = "openocd"
3) Project with both profiles and extra args
[project]
# global extra args (applies to all profiles)
args = {
build = ["-j", "0"],
run = ["wait_uart"]
}
[profile.dev]
board = "native_sim"
runner = "native"
# dev profile specific extra args
args = {
build = ["-DKAZE_TEST=ON"],
run = ["-flash=seed/flash.bin"],
}
[profile.prod]
board = "nucleo_f767zi"
runner = "openocd"
Verbosity
Kaze emits user-facing logs prefixed with kaze: and uses colored logs if
colour output is supported by the terminal.
Verbosity levels:
-v(1): quiet — no kaze logs, no command output- default /
-vv(2): normal — kaze logs only; command output only on error -vvv+ (3+): verbose — kaze logs + command output always
Environment variables:
KAZE_TESTING=1suppresses logs (useful for tests).KAZE_LOGS=1re-enables logs during tests.
Typical workflow
Let's say you have a Zephyr app like this:
app
├── boards
│ └── ...
├── include
│ └── ...
├── src
│ └── ...
├── CMakeLists.txt
├── LICENSE
├── prj.conf
└── README.md
- Initialize the project with a
kaze.toml, either manually or use:
kaze init
This will create a kaze.toml file with some default settings:
app
├── boards
│ └── ...
.
.
.
├── README.md
└── kaze.toml # <- kaze project config
# kaze.toml
#edit this configuration at your discretion
# Project config
[project]
board = "nucleo_f767zi"
runner = "openocd"
# args = { conf = [""], build = [""], run = [""], flash = [""] }
# default_profile = "sim"
# Build dir config
[build]
root = "build"
# Zephyr workspace override
# [zephyr]
# workspace = ""
# base = ""
# SPDX BoM generation
# [bom]
# build = true
# version = "2.2"
# Build profiles
# [profile.sim]
# board = "native_sim"
# runner = "native"
# args = { conf = [""], build = [""], run = [""], flash = [""] }
# [profile.prod]
# args = { conf = [""], build = [""], run = [""], flash = [""] }
- Configure and build the app:
kaze conf # <- optional step, as kaze build will configure project as well if not configured
kaze build
- Flash app
kaze flash
or if using one of Zephyr's simulator boards (native_sim or qemu boards) run
simulation:
kaze run
Sysbuild projects
When building a sysbuild project the workflow looks pretty much the same:
- Init project with kaze config
- Config + build project
- Flash project images / run simulations
Sysbuild image selection
Sysbuild projects often consist of multiple standalone apps all built by
sysbuild. Let's consider a sysbuild project consisting of the mcuboot
bootloader and a simple app compatible with mcuboot (let's call it just
app), so the project would look something like this:
app
├── boards
│ └── ...
├── keys # keys to sign our app and mcuboot
│ └── ...
├── src
│ └── ...
├── sysbuild # additional sysbuild image configs
│ └── mcuboot.conf # in our case that is mcuboot
├── CMakeLists.txt # app cmake config
├── LICENSE
├── prj.conf # app kconfig
├── README.md
├── sysbuild.conf # sysbuild config
└── kaze.toml # already initialized with kaze config
This app, when built, would produce 2 separate images:
| Image | Description |
|---|---|
app |
Our app compatible with mcuboot |
mcuboot |
Mcuboot bootloader image |
You can list available images with the --list option passed to run, flash,
menuconfig and bom commands:
kaze flash --list
Output:
...
Available sysbuild images:
1: app
2: mcuboot
To select an image to flash/run use the --image option and pass in either the
image name (e.g. app) or the image number (e.g. 1):
kaze flash --image app
or
kaze flash --image 1
If no image selected, kaze will default to the first non-bootloader image available.
SPDX BoM generation
To be able to generate SPDX BoMs, enable the [bom.build] option in kaze
config. BoMs can only be genrated from built binaries pre-configured for BoM
generation. If a binary is built without BoM support and you enable it, kaze
automatically configures and rebuilds it when running kaze bom.
Workspace management
kaze is able to manage Zephyr workspaces through west.yml manifest files or
repositories using west. To manage a zephyr workspace use the kaze workspace
command:
Usage: kaze workspace <COMMAND>
Commands:
init Initialize workspace from a url or a manifest file
update Update workspace
export Exports workspace cmake package
apply Apply workspace by running init, update and export
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
-V, --version Print version
kaze supports all workspace topologies, given the [zephyr] table of kaze
config is set up correctly.
🔔 Note:
[zephyr.url]and[zephyr.manifest]settings are mutually exclusive.
Example app
For a simple example Zephyr app managed by kaze see
kaze-demo
Similar projects
License
This project is licensed under either of:
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed under the Apache-2.0 and MIT license, without any additional terms or conditions.
Development
TLDR:
Requires just to bootstrap all tools and configuration
cargo install just
just init # setup repo, install hooks and all required tools
To run:
just run
To test:
just test
Before committing work:
just pre-commit
To see all available commands:
just list
Upcomming features
- Menuconfig
- SPDX BoMs
- Zephyr workspace management
- Key generation for mcuboot bootloader and images
- Manual image signing
- Debugging apps
- Project template generation (app, module, sysbuild project, ...)
- Reference config values in string config options
Dependencies
~3–6MB
~112K SLoC