Build System
OpenSMA’s build has two layers: the top-level orchestrator
mcu_build.sh, and the UBS make system under corepdk/ubs/ that it
invokes through the ./ubs wrapper. This chapter traces both.
Entry point: mcu_build.sh
mcu_build.sh parses KEY=value arguments (mcu_build.sh:20); the
usage banner lists them all (mcu_build.sh:6):
| Selector | Meaning | Example |
|---|---|---|
PROJECT |
Buildable project (src/projects/<name>) |
mcxn547helloworld |
PLATFORM |
SoC/core platform | mcxn556-both |
BOARD |
Board variant (src/boards/<name>) |
mcxn547helloworld |
MODE |
Build mode (opt/debug) | rel, dev |
SIGN_KEYSET |
Signing keyset | local, local-prod, S0 |
VERSION |
Firmware version string | 02.0020.0000 |
STREAMBOOT |
Emit multi-binary streaming image | 1 |
RUN_LOCAL |
Run outside the UBS Docker image | 1 |
BUILD_ONLY |
Build without signing/downloading | 1 |
Unset selectors fall back to *_ENV environment variables
(mcu_build.sh:36). The toolchain root defaults to /toolchain
(mcu_build.sh:44) and the build/sign container defaults to a pinned
UBS_DOCKER image (mcu_build.sh:45).
The build flow
run_build_flow() (mcu_build.sh:61) assembles the per-core
environment and drives the build. For the dual-core “both” platforms it
builds core1 first and embeds it into core0 — see
Architecture.
The actual build is a UBS make invocation assembled into
BUILD_CMD="./ubs build" (mcu_build.sh:211) with the selectors
appended, then eval‘d. ./ubs is a symlink to corepdk/ubs/ubs, the
make front-end; the build tree, plugins, and share files live under
corepdk/ubs/.
flowchart LR
A[mcu_build.sh] --> B[run_build_flow]
B --> C["./ubs build<br/>(corepdk/ubs)"]
C --> D{STREAMBOOT=1?}
D -->|yes| E["./ubs multi-bin"]
D -->|no| F
E --> F{BUILD_ONLY=1?}
F -->|yes| Z[stop]
F -->|no| G["./ubs local-sign<br/>(if SIGN_KEYSET=local*)"]
G --> H[signed image in build/]
Make fragments (etc/)
UBS composes a build from make fragments under etc/:
| Directory | Role |
|---|---|
etc/platforms/ |
Per-platform makefiles (mcxn236.mk, mcxn556-core0.mk, mcxn556-core1.mk, mcxn547-*.mk, x86.mk) and configs (nvheader-cfg.json, pldmfw-cfg-*.json) |
etc/projects/ |
Per-project/module makefiles (mcxn547helloworld*.mk, module-mctp-cpp.mk, module-pldm-fd.mk, module-spdm.mk, nvheader.mk) |
etc/plugins/ |
Build plugins: local-sign.mk, sign-request.mk, sign-download.mk, flash.mk, multi-bin.mk, nv-coverage-check.mk, ubs-format.mk, ubs-module.mk |
etc/features.mk |
Feature toggles (etc/features.mk) |
This fragment layout is why adding a platform or project is mostly a
matter of dropping the right .mk files under etc/platforms/ and
etc/projects/.
Signing and keysets
After a successful build (and unless BUILD_ONLY=1,
mcu_build.sh:253), signing runs. core1-only platforms are not
signed (mcu_build.sh:258). Local signing triggers when SIGN_KEYSET
starts with local (mcu_build.sh:265) and assembles
./ubs local-sign (mcu_build.sh:268):
SIGN_KEYSET=local/local-debug→KEY_TYPE=DEBUGSIGN_KEYSET=local-prod→KEY_TYPE=PROD
The signing make logic lives in etc/plugins/local-sign.mk, which
pulls in etc/plugins/sign-request.mk
(etc/plugins/local-sign.mk:19) and branches per chip. Non-local
keysets (e.g. S0) route to the request/download signing plugins
(sign-request.mk, sign-download.mk) instead. Signing uses NXP’s
spsdk (installed in Setup).
Streaming boot & multi-binary
With STREAMBOOT=1, mcu_build.sh additionally runs
./ubs multi-bin (mcu_build.sh:232) to emit the multi-binary
streaming image, governed by etc/plugins/multi-bin.mk.
Docker vs local
By default the build/sign steps run inside the pinned UBS Docker image
(mcu_build.sh:45); RUN_LOCAL=1 runs them directly on the host
instead. The image is built from libexec/ubs.dockerfile
(see Setup).
Next
- Reference — lint/format/doxygen tooling and CI.
- Transports & Buses — into the firmware subsystems.