14 Commits

Author SHA1 Message Date
Joel Winarske 8417e3a0e8 docs(cross): document + demonstrate app-layer extends
Add a README subsection ("Layered manifests: extends, board → project → app")
covering both extends forms (<board> and <dir>#<target>) and the merge rules,
with project and app manifest snippets.

Add examples/cross/app-extends.emb.yaml: an app target that extends the rpi
family file's rpi5-bookworm target (which extends the board) and overlays an
app-specific dev package — a real three-layer chain. A cross_command test
--dry-runs it so it stays valid.

Signed-off-by: Joel Winarske <joel.winarske@gmail.com>
2026-06-20 07:13:21 -07:00
Joel Winarske 030efc9588 feat(cross): board library + manifest extends (cross-layer resolution)
Factor the hardware/OS facts out of project manifests into a board library
that ships with emb, and let manifests `extends` it. Resolution merges the
layers: emb board (hardware) <- project (embedder) [<- app, future].

- boards/raspberry-pi.emb.yaml: hardware-only base for rpi{5,4,zero-2w} x
  {bookworm,trixie} — provider, triple, per-OS toolchain+image+partition,
  per-model cpu_flags, base GUI/input/Vulkan stack. Located at runtime via the
  emb_cli package_config (override with EMB_BOARDS_DIR or the resolver arg).
- cross.extends: <board> in a target deep-merges the project layer over the
  named board, recursing for chains. Merge rules: maps deep-merge; cpu_flags
  and backends replace (per-model / complete statement); sysroot.dev_packages
  union (board base + project additions, deduped).
- examples/cross/raspberry-pi-family.emb.yaml now `extends` the boards and
  carries only the project layer (backends, augment, plugin packages) — the
  hardware duplication is gone.
- Fix cross_command_test target names for the expanded example (#51).

Validated: extends resolves in the real CLI via package_config auto-discovery;
--list-targets + --dry-run show hardware-from-board + project overlay; new
resolver tests cover inherit/override/union/replace/unknown-board. 294 pass.

Signed-off-by: Joel Winarske <joel.winarske@gmail.com>
2026-06-19 16:44:45 -07:00
Joel Winarske eae0f7650a feat(examples): full Raspberry Pi family manifest (rpi4/5/zero-2w x bookworm/trixie)
Expand the rpi family example from a single bookworm/drm-kms-egl board into the
six targets the ivi-homescreen PiOS CI needs: {rpi5, rpi4, rpi-zero-2w} x
{bookworm, trixie}.

- OS variant drives toolchain + sysroot (and thus the container image):
  bookworm -> 12.3.rel1 + raspios-bookworm; trixie -> 15.2.rel1 + raspios-trixie.
  bookworm cross-builds libdisplay-info 0.2.0 (ships 0.1.1, drm-cxx needs >=0.2.0)
  and omits the apt libdisplay-info-dev so the static .a isn't shadowed; trixie
  keeps it. Vulkan headers are vendored by ivi-homescreen + drm-cxx, so neither
  OS stages them.
- Board only changes -mcpu (a76/a72/a53); all three share one sysroot per OS.
- Backends: rpi5 builds all five (incl. drm-kms-vulkan); rpi4 and zero-2w build
  the four without it. Plugins on (PLUGINS_DIR=../ivi-homescreen-plugins).

Validated: parses, --list-targets shows the right per-model backend sets, and
--dry-run resolves each target's toolchain/image/cpu/augment. Example tests pass.

Signed-off-by: Joel Winarske <joel.winarske@gmail.com>
2026-06-19 13:48:50 -07:00
Joel Winarske de6cabe1d2 feat(cross): make radxa zero3 buildable (all 3 backends)
Turns the radxa_zero3 example into a build-validated manifest and adds
the two sysroot capabilities its bookworm-KDE image needs.

- apt_resolver: explicit dev_packages roots are always staged, even when
  dpkg-status marks them installed — a device image often records a
  package installed yet strips its files (e.g. linux-libc-dev). Transitive
  deps keep the already-installed prune.
- cross.sysroot.symlinks: declare in-sysroot symlinks created after dev
  staging (link path skipped if it already exists). Folded into sysrootKey.
- arm-gnu provider applies the symlinks after dev-package staging.
- radxa_zero3.emb.yaml: validated end-to-end — rootfs partition 3 (p2 is
  boot), dev_packages, a drm->libdrm symlink (radxa's vendor linux-libc-dev
  omits /usr/include/drm/), and the three board backends (wayland-egl,
  drm-kms-egl, software). emb cross . --build --deb produced aarch64 ELFs
  + .debs for all three.

Tests: resolver root-always-staged, symlink parse + sysrootKey effect,
radxa example fields. examples/cross/README documents partition/symlinks.

Signed-off-by: Joel Winarske <joel.winarske@gmail.com>
2026-06-19 09:53:07 -07:00
Joel Winarske 0aa4dfbda3 docs(cross): make agl_sdk_local buildable, at parity with agl_sdk_url
agl_sdk_local was resolve-only (sdk_path + triple, no backends). Bring it
to parity with the now-buildable agl_sdk_url: host_build_tools (AGL pins
cmake 3.16.5), the wayland-egl backend + ENABLE_AGL_SHELL_CLIENT, and a
package block — the same recipe, just an installed SDK root (sdk_path)
instead of a URL. Update the example-parse test and cross-reference it
from the 'Building for AGL' how-to.

Signed-off-by: Joel Winarske <joel.winarske@gmail.com>
2026-06-18 15:41:47 -07:00
Joel Winarske 06bbbeed85 feat(manifest): read cross: into EmbManifest.cross
EmbManifest.fromMap now parses the cross: block into a typed
EmbManifest.cross (CrossTarget?), so a package's own emb.yaml can
self-describe its cross toolchain/sysroot instead of needing a separate
file. Parsing never throws — a malformed cross: (e.g. a multi-target
block whose provider lives only under targets) yields null rather than
breaking the manifest load for unrelated commands (deps/sync/doctor).
For a multi-target block it surfaces the shared base; CrossProjectResolver
still does per-target merging.

Closes the 'Surfacing cross:' gap noted in examples/cross/README.md.

Signed-off-by: Joel Winarske <joel.winarske@gmail.com>
2026-06-18 15:12:42 -07:00
Joel Winarske e343360492 docs(cross): make the AGL SDK example buildable + add an AGL how-to
The committed agl_sdk_url example pointed at a dead jellyfish 10.93.1 URL
and was resolve-only. Replace it with a complete, validated AGL build
manifest and document the flow.

- agl_sdk_url.emb.yaml: live AGL Marlin 13.0.3 archive sdk_url,
  host_build_tools (AGL pins cmake 3.16.5 < ivi-homescreen's 3.20 floor),
  wayland-egl backend + ENABLE_AGL_SHELL_CLIENT (agl-compositor shell),
  and a package block. Builds an aarch64-agl homescreen ELF end to end.
- examples/cross/README.md: a 'Building ivi-homescreen for AGL' section
  with the cross block, the copy-next-to-source + --build --host-tools
  flow, the three AGL specifics (triple, agl-shell, host cmake), the
  emb.lock note, and the download->archive URL caveat.
- Update the example-parse test to the new manifest; allowlist
  automotivelinux/libwayland/nativesdk for cspell.

Signed-off-by: Joel Winarske <joel.winarske@gmail.com>
2026-06-18 15:00:19 -07:00
Joel Winarske 82a02a93d5 feat(cross): resolve a project .emb/ directory of per-board manifests
Point `emb cross` at a project directory and it now prefers a `.emb/`
manifest directory over a top-level emb.yaml. The selectable target list
is the union across every `.emb/*.emb.yaml`: a flat per-board file
contributes one target (named by its platform.name), and a family file
contributes one per cross.targets entry (image-sharing boards like
rpi4/rpi5), grouped under the family. `--list-targets` shows the union
plus the built-in native local; `--target` selects from it.

Resolution merges three layers: an optional `.emb/base.emb.yaml` shared
base is deep-merged under each board file (nested maps such as
cross.sysroot combine, so base defaults survive what a board omits),
then a cross.targets variant shallow-overrides. A board's cross.backends
replaces the base's rather than unioning with it, so a drm-kms board does
not inherit a wayland default.

Single-file manifests and in-file cross.targets keep working unchanged
(a flat file's sole target stays the default; a multi-target file still
requires --target, else native local). Duplicate target names across
files, and a target named local/host, are usage errors.

New lib/src/cross/cross_project.dart (CrossProjectResolver, CrossProject,
CrossTargetRef, deepMerge) replaces the inline cross-map selection in
cross_command. examples/cross/project/.emb/ demonstrates a base + a
Raspberry Pi family file + a flat i.MX93 file.

Signed-off-by: Joel Winarske <joel.winarske@gmail.com>
2026-06-18 08:41:36 -07:00
Joel Winarske 179b538539 fix(cross): build-all-backends.sh uses this checkout's emb
The wrapper ran whatever `emb` was on PATH, which fails if the global emb
predates --target/--backend. Default to `dart run <repo>/bin/emb.dart` (this
checkout) so it works on a feature branch before emb is re-installed; EMB=...
overrides. Source dir is absolutized and cwd preserved.

Signed-off-by: Joel Winarske <joel.winarske@gmail.com>
2026-06-16 16:57:56 -07:00
Joel Winarske a99f2344aa docs(cross): add build-all-backends.sh wrapper
A tiny script that drops all-backends.emb.yaml next to a given ivi-homescreen
checkout and runs `emb cross … --target local --build` for every backend.
Extra args (e.g. --backend, --deb) pass through.

Signed-off-by: Joel Winarske <joel.winarske@gmail.com>
2026-06-16 16:52:39 -07:00
Joel Winarske bacb50d8bf docs(cross): add all-backends example for native multi-backend builds
Move the "build every ivi-homescreen backend" manifest into examples/cross/ as
a tracked reference. It builds all six backends (wayland-egl/-vulkan,
drm-kms-egl/-vulkan, software, headless-egl) natively via the built-in `local`
target, exercising the cross.backends matrix + a shared cross.defines
(DISABLE_PLUGINS). Documented in the examples README; added a --dry-run test.

Signed-off-by: Joel Winarske <joel.winarske@gmail.com>
2026-06-16 16:51:19 -07:00
Joel Winarske 088941bdd8 feat(cross): multi-platform manifests via cross.targets + --target
Switch between boards (rpi4/rpi5/rpi-zero-2w/radxa-zero3, …) from a single
manifest. Shared config lives at the cross: level; each platform under
cross.targets overrides only what differs (image_url, cpu_flags). Select one
with --target <name>; --list-targets prints the defined platforms. A manifest
with no targets behaves exactly as before (one implicit target).

Working dirs are content-hash keyed via a two-tier scheme so same-triple boards
no longer collide and identical sysroots are shared:
- sysrootKey (excludes cpu_flags) names the toolchain+sysroot dir, so cpu-only
  variants on one image (rpi4/rpi5/zero-2w) share a single extraction.
- buildKey (full config) names the per-board build dir; the emitted cmake
  toolchain file is cpu-named so variants coexist in the shared sysroot dir.
A different image (radxa) gets its own sysroot.

cross-build/cross/yocto-sdk dirs and --clean are updated to the keyed names.
Adds examples/cross/raspberry-pi-family.emb.yaml and README docs.

Signed-off-by: Joel Winarske <joel.winarske@gmail.com>
2026-06-16 16:19:41 -07:00
Joel Winarske dbb99d9573 docs(cross): document emb cross flags and the validated pi5 example
Add an `emb cross` command reference to the README covering every flag
(--dry-run, --prepare, --build, --deb, --clean, --clean-all) plus the cross:
manifest schema. Make examples/cross/pi5.emb.yaml the end-to-end validated
manifest — the exact config that builds an aarch64 binary and packages a .deb
(sysroot.dev_packages, drm-kms-egl backend, package: block); drop the untested
vulkan-headers augment. Document the validated build/deb/clean workflow in
examples/cross/README.md. Update the coupled example test and the spell-check
dictionary.

Signed-off-by: Joel Winarske <joel.winarske@gmail.com>
2026-06-16 14:16:31 -07:00
Joel Winarske f410470148 feat(cross): add manifest-driven cross-compile layer + L1 tests
Fold ivi-homescreen's build_*.sh into a manifest `cross:` block. One
CrossProfile (toolchain + sysroot(s) + flags + pkg-config + emitted build
files) is produced by three providers and consumed downstream uniformly:

- spine: cross_target, cross_profile, cross_provider, toolchain_emitter
- providers: arm-gnu (image/device sysroot; pinned/derive toolchain),
  yocto-recipe (located recipe-sysroot), yocto-sdk (sources the OE env);
  overlay_builder + an injectable process_runner seam
- `emb cross <pkg> [--prepare]` resolves the profile and optionally builds
  augment libs into an isolated overlay (never the shared sysroot)
- 7 example manifests (one per board) + README

L1 hermetic tests (fixtures + the ProcessRunner seam) cover the parse layer,
all three providers, the emitter, and the overlay builder — 44 cross tests,
coverage 51.91% (>= the 45 gate). The I/O-heavy image/device/installer paths
are left for L2 (real host/network).

The optional EmbManifest typed `cross` field is deferred: parsing cross:
during manifest load would throw an uncaught ArgumentError on a bad provider
token; cross_command reads manifest.raw['cross'] and reports it cleanly.

Signed-off-by: Joel Winarske <joel.winarske@gmail.com>
2026-06-16 09:52:20 -07:00