mirror of
https://github.com/toyota-connected/emb_cli.git
synced 2026-06-21 07:19:37 -07:00
feat: auto-resolve PackageKit native bridge; use hosted packagekit_dart
- Depend on the published `packagekit_dart ^0.3.2` instead of a path dependency. - native_lib.dart: locate `libpackagekit_nc.so` from the package's own build or, for hosted installs, the `package:hooks` build-hook output under `.dart_tool/`, so the Linux backend works without `PK_NC_LIB`. - docs: full per-command README reference (every option, default, value set); add `example/`; refresh CHANGELOG. - chore: whitelist `Kitware`, `armv`, `armhf` for cspell. Signed-off-by: Joel Winarske <joel.winarske@gmail.com>
This commit is contained in:
@@ -21,6 +21,8 @@
|
||||
"aarch",
|
||||
"aotruntime",
|
||||
"archs",
|
||||
"armhf",
|
||||
"armv",
|
||||
"Brewfile",
|
||||
"cmake",
|
||||
"cpp",
|
||||
@@ -35,6 +37,7 @@
|
||||
"glibc",
|
||||
"homescreen",
|
||||
"icudtl",
|
||||
"Kitware",
|
||||
"libapp",
|
||||
"libc",
|
||||
"libflutter",
|
||||
|
||||
@@ -16,6 +16,13 @@ Port of `meta-flutter/workspace-automation` to a Dart CLI.
|
||||
matrix.
|
||||
- feat: `emb setup` — one-shot provision; emits `setup_env.sh`.
|
||||
- feat: `emb env` — write `setup_env.sh`.
|
||||
- feat: depend on the published `packagekit_dart` `^0.3.2` (hosted, not a path
|
||||
dependency).
|
||||
- feat: auto-resolve the PackageKit native bridge (`libpackagekit_nc.so`) — from
|
||||
the package's own build or, for hosted installs, the `package:hooks` build-hook
|
||||
output under `.dart_tool/` — so the Linux backend works without `PK_NC_LIB`.
|
||||
- docs: full per-command reference (every option, default, and value set) in the
|
||||
README; add `example/`.
|
||||
|
||||
# 0.0.1
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ deployable app bundles for embedders such as
|
||||
port of [meta-flutter/workspace-automation](https://github.com/meta-flutter/workspace-automation)
|
||||
(`flutter_workspace.py` + `create_aot.py`).
|
||||
|
||||
It does the whole flow in a handful of commands:
|
||||
The whole flow is a handful of commands:
|
||||
|
||||
```
|
||||
deps → repos → Flutter SDK → engine → AOT → ivi-homescreen bundle
|
||||
@@ -21,32 +21,44 @@ deps → repos → Flutter SDK → engine → AOT → ivi-homescreen bundle
|
||||
[meta-flutter/flutter-engine](https://github.com/meta-flutter/flutter-engine)
|
||||
releases (auto, keyed by the SDK's engine commit).
|
||||
- **Cross-compile AOT** for `arm64` / `riscv64` from an `x86_64` host using the
|
||||
engine's simulator `gen_snapshot` (no qemu — the artifact is self-contained).
|
||||
- **Self-describing packages**: a package declares its build in its manifest and
|
||||
`emb build <package>` does the rest.
|
||||
engine's simulator `gen_snapshot` — no qemu (the artifact is self-contained).
|
||||
- **Self-describing packages**: a package declares its build in a manifest and
|
||||
`emb build <dir>` does the rest.
|
||||
|
||||
---
|
||||
|
||||
## Requirements
|
||||
|
||||
- Dart SDK ≥ 3.10.1 (the `emb` tool itself).
|
||||
- Linux for host **dependency install** (PackageKit — dnf/apt/zypper). The
|
||||
macOS/Windows package backends are stubbed in this build.
|
||||
- `git`, `tar`, `curl` on PATH.
|
||||
- **Dart SDK ≥ 3.10.1** (to run/build the `emb` tool itself).
|
||||
- **Linux** for host **dependency install** (PackageKit — dnf/apt/zypper). The
|
||||
macOS (Homebrew) and Windows (WinGet) backends are stubbed in this build; all
|
||||
other commands are cross-platform.
|
||||
- `git`, `tar`, `curl` on `PATH`.
|
||||
- Cross-compiling to a device arch is supported **from an x86_64 host**.
|
||||
|
||||
---
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
# From this directory:
|
||||
# From the package root:
|
||||
dart pub get
|
||||
dart pub global activate --source=path .
|
||||
dart pub global activate --source=path . # puts `emb` on PATH
|
||||
|
||||
# Then (ensure the pub-global bin dir is on PATH):
|
||||
emb --help
|
||||
```
|
||||
|
||||
You can also run it without activating: `dart run bin/emb.dart <command>`.
|
||||
Make sure the pub-global bin dir (`$PUB_CACHE/bin`, e.g. `~/.pub-cache/bin`) is
|
||||
on `PATH`. You can also run without activating:
|
||||
|
||||
```sh
|
||||
dart run bin/emb.dart <command> # from the package root
|
||||
```
|
||||
|
||||
> The Linux backend loads `packagekit_dart`'s native bridge
|
||||
> (`libpackagekit_nc.so`). `emb` locates it automatically — from the package's
|
||||
> own build, or from the `package:hooks` build-hook output under
|
||||
> `.dart_tool/`. Override with `PK_NC_LIB=/path/to/libpackagekit_nc.so`.
|
||||
|
||||
---
|
||||
|
||||
@@ -69,114 +81,324 @@ emb bundle --app-path ./app/my_app --arch arm64 --build
|
||||
# ivi-homescreen --b=<workspace>/bundle/my_app-release-arm64
|
||||
```
|
||||
|
||||
`emb setup` runs everything; you can also run the phases individually
|
||||
(`emb deps`, `emb sync`, `emb flutter`, `emb engine`). The workspace root is
|
||||
`$FLUTTER_WORKSPACE`, else the current directory, else `--workspace <dir>`.
|
||||
`emb setup` runs every phase; you can also run them individually
|
||||
(`emb deps`, `emb sync`, `emb flutter`, `emb engine`).
|
||||
|
||||
---
|
||||
|
||||
## Building bundles
|
||||
## Workspace & path resolution
|
||||
|
||||
A bundle is the directory layout `ivi-homescreen` consumes:
|
||||
Every command that touches the workspace resolves its root **in this order**:
|
||||
|
||||
1. `--workspace <dir>` (explicit flag), else
|
||||
2. the `$FLUTTER_WORKSPACE` environment variable, else
|
||||
3. the current working directory.
|
||||
|
||||
```
|
||||
<workspace>/ # the resolved root
|
||||
app/ # cloned source repositories
|
||||
flutter/ # Flutter SDK
|
||||
bundle/ # built bundles (default output)
|
||||
setup_env.sh # generated environment script
|
||||
.config/flutter_workspace/
|
||||
flutter-engine/<commit>/... # downloaded + extracted engine SDKs
|
||||
flutter-engine/bundle-<mode>-<arch>/ # staged engine halves (icudtl + .so)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Command reference
|
||||
|
||||
```
|
||||
emb <command> [arguments]
|
||||
```
|
||||
|
||||
### Global options
|
||||
|
||||
| Option | Description |
|
||||
|---|---|
|
||||
| `-h`, `--help` | Print usage. Works at the top level and per command (`emb <cmd> --help`). |
|
||||
| `-v`, `--version` | Print the CLI version. |
|
||||
| `--[no-]verbose` | Noisy logging, including every shell command executed. |
|
||||
|
||||
`--workspace` (`-w`), shown on most commands, follows the resolution order
|
||||
above. `--mode`/`--arch` defaults and value sets differ **per command** — see
|
||||
each entry.
|
||||
|
||||
---
|
||||
|
||||
### `emb doctor`
|
||||
|
||||
Report host detection (os / arch / distro) and package-manager backend
|
||||
availability. No options. Exit code is non-zero if the backend is unavailable.
|
||||
|
||||
```sh
|
||||
emb doctor
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `emb setup`
|
||||
|
||||
One-shot provision: **deps → repos → Flutter SDK → engine**, then writes
|
||||
`setup_env.sh`. Each phase is individually skippable.
|
||||
|
||||
| Option | Default | Description |
|
||||
|---|---|---|
|
||||
| `-c`, `--config <dir>` | `configs` | Legacy JSON config directory. |
|
||||
| `-p`, `--packages <dir>` | — | Directory to discover self-describing `emb` manifests. |
|
||||
| `-w`, `--workspace <dir>` | resolution order | Workspace root. |
|
||||
| `--flutter-version <ref>` | `globals.json` `flutter_version` | Flutter version/tag/branch. |
|
||||
| `--arch <arch>` | host arch | Engine arch to prefetch. |
|
||||
| `-m`, `--mode <mode>` | `release` | Engine runtime modes to prefetch (repeatable): `release`, `profile`, `debug`. |
|
||||
| `-y`, `--yes` | off | Skip the deps confirmation prompt (CI). |
|
||||
| `--skip-deps` | off | Skip host dependency install. |
|
||||
| `--skip-sync` | off | Skip repository sync. |
|
||||
| `--skip-flutter` | off | Skip Flutter SDK install. |
|
||||
| `--skip-engine` | off | Skip engine artifact fetch. |
|
||||
|
||||
```sh
|
||||
emb setup --config ../configs --yes
|
||||
emb setup --config ../configs --skip-deps --skip-sync # SDK + engine only
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `emb deps`
|
||||
|
||||
Coalesce host dependencies across all selected manifests, filter to what's
|
||||
**missing** on this host, and install the union in **one** transaction.
|
||||
|
||||
| Option | Default | Description |
|
||||
|---|---|---|
|
||||
| `-c`, `--config <dir>` | `configs` | Legacy JSON config directory. **Repeatable.** |
|
||||
| `-p`, `--packages <dir>` | — | Directory to discover self-describing `emb` manifests. **Repeatable.** |
|
||||
| `--dry-run` | off | Resolve and print the install plan without changing the system. |
|
||||
| `-y`, `--yes` | off | Skip the confirmation prompt (CI). |
|
||||
|
||||
```sh
|
||||
emb deps --config ../configs --dry-run # plan only
|
||||
emb deps --config ../configs --yes # install in one transaction
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `emb sync`
|
||||
|
||||
Clone/update source repositories into `<workspace>/app` (bounded concurrency).
|
||||
|
||||
| Option | Default | Description |
|
||||
|---|---|---|
|
||||
| `-c`, `--config <dir>` | `configs` | Legacy JSON config directory. **Repeatable.** |
|
||||
| `-p`, `--packages <dir>` | — | Directory to discover self-describing `emb` manifests. |
|
||||
| `--repos <file>` | — | A JSON file containing a bare array of repo entries. **Repeatable.** |
|
||||
| `-w`, `--workspace <dir>` | resolution order | Workspace root. |
|
||||
| `-j`, `--concurrency <n>` | `4` | Maximum concurrent git operations. |
|
||||
|
||||
```sh
|
||||
emb sync --config ../configs -j 8
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `emb flutter`
|
||||
|
||||
Install the Flutter SDK into `<workspace>/flutter`.
|
||||
|
||||
| Option | Default | Description |
|
||||
|---|---|---|
|
||||
| `-w`, `--workspace <dir>` | resolution order | Workspace root. |
|
||||
| `--flutter-version <ref>` | `globals.json` `flutter_version` | Version/tag/branch to check out. |
|
||||
| `-c`, `--config <dir>` | `configs` | Directory to read `globals.json` from. |
|
||||
| `--configure` | off | Run `flutter config` (desktop + custom devices) and `flutter doctor` after install. |
|
||||
|
||||
```sh
|
||||
emb flutter --flutter-version 3.44.2 --configure
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `emb engine`
|
||||
|
||||
Fetch prebuilt Flutter engine artifacts (auto fetch-else-build). Modes you don't
|
||||
fetch here are auto-fetched on demand by `emb bundle`/`emb build`.
|
||||
|
||||
| Option | Default | Description |
|
||||
|---|---|---|
|
||||
| `-w`, `--workspace <dir>` | resolution order | Workspace root. |
|
||||
| `--commit <sha>` | `<workspace>/flutter/bin/internal/engine.version` | Engine commit to fetch. |
|
||||
| `--arch <arch>` | host arch | Engine arch token (see [Architectures](#architectures--cross-compiling)). |
|
||||
| `-m`, `--mode <mode>` | `release` | Runtime modes to fetch (repeatable): `release`, `profile`, `debug`. |
|
||||
| `--clean` | off | Re-stage bundles even when already present. |
|
||||
| `--check` | off | Only check prebuilt availability; do not download. |
|
||||
|
||||
```sh
|
||||
emb engine --arch arm64 --mode release --mode profile
|
||||
emb engine --arch riscv64 --check # is a prebuilt available?
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `emb aot`
|
||||
|
||||
Build the AOT image (`libapp.so`) for a Flutter app — the AOT primitive used by
|
||||
`emb bundle --build`. **Debug is not AOT**, so only `release`/`profile` apply.
|
||||
|
||||
| Option | Default | Description |
|
||||
|---|---|---|
|
||||
| `-a`, `--app-path <dir>` | **mandatory** | Path to the Flutter application to build. |
|
||||
| `-w`, `--workspace <dir>` | resolution order | Workspace root. |
|
||||
| `-m`, `--mode <mode>` | `release` | Runtime modes to build (repeatable): `release`, `profile`. |
|
||||
| `--arch <arch>` | host arch | Target arch for `gen_snapshot` (e.g. `arm64` for a Pi). |
|
||||
| `--gen-snapshot <path>` | auto-resolved | Explicit `gen_snapshot` path (overrides resolution). |
|
||||
| `--glibc-sysroot <dir>` | artifact's bundled `clang_x64/lib64` | Directory with `ld-linux` + libc to run `gen_snapshot` under. |
|
||||
|
||||
```sh
|
||||
emb aot --app-path ./app/my_app --arch arm64 --mode release --mode profile
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `emb bundle`
|
||||
|
||||
Assemble an ivi-homescreen bundle from app + engine artifacts. With `--build` it
|
||||
runs `emb aot` first; the engine SDK for the `(mode, arch)` is fetched
|
||||
implicitly if not already cached.
|
||||
|
||||
| Option | Default | Description |
|
||||
|---|---|---|
|
||||
| `-a`, `--app-path <dir>` | **mandatory** | Path to the Flutter application. |
|
||||
| `-w`, `--workspace <dir>` | resolution order | Workspace root. |
|
||||
| `-m`, `--mode <mode>` | `release` | Single mode: `debug` (JIT, no AOT), `profile`, or `release` (AOT). |
|
||||
| `--arch <arch>` | host arch | Target arch (e.g. `arm64`). |
|
||||
| `-o`, `--output <dir>` (alias `--out`) | `<workspace>/bundle/<app>-<mode>-<arch>` | Output bundle directory — any path. |
|
||||
| `--build` | off | Run `emb aot` first to (re)build `flutter_assets` + `libapp.so`. |
|
||||
|
||||
```sh
|
||||
emb bundle --app-path ./app/my_app --arch arm64 --build # release
|
||||
emb bundle --app-path ./app/my_app --arch arm64 --build --mode debug # JIT
|
||||
emb bundle --app-path ./app/my_app --arch riscv64 --build --mode profile
|
||||
emb bundle --app-path ./app/my_app --build # host
|
||||
emb bundle --app-path ./app/my_app --arch arm64 --output /tmp/out # custom path
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `emb build`
|
||||
|
||||
Build a **self-describing** package — a directory with an `emb.yaml` (or an
|
||||
`emb:` key in `pubspec.yaml`) — into bundles, using the manifest's `build:`
|
||||
matrix. The package directory is a **positional argument** (mandatory; omitting
|
||||
it prints a usage error).
|
||||
|
||||
```
|
||||
emb build <package-dir> [options]
|
||||
```
|
||||
|
||||
| Option | Default | Description |
|
||||
|---|---|---|
|
||||
| `<package-dir>` | **mandatory (positional)** | Directory containing `emb.yaml` or a `pubspec.yaml` with an `emb:` key. |
|
||||
| `-w`, `--workspace <dir>` | resolution order | Workspace root. |
|
||||
| `--arch <arch>` | manifest's `archs` | Override target arch(es). **Repeatable.** |
|
||||
| `-m`, `--mode <mode>` | manifest's `modes` | Override mode(s): `debug`, `profile`, `release`. **Repeatable.** |
|
||||
| `--no-build` | off | Assemble from existing artifacts; skip compiling. |
|
||||
|
||||
```sh
|
||||
emb build ./app/my_app # full manifest matrix
|
||||
emb build ./app/my_app --arch arm64 --mode release # override the matrix
|
||||
emb build ./app/my_app --no-build # assemble only
|
||||
```
|
||||
|
||||
#### Manifest (`emb.yaml`)
|
||||
|
||||
```yaml
|
||||
id: my_app
|
||||
type: app
|
||||
build:
|
||||
app_path: . # Flutter app dir, relative to this manifest (default ".")
|
||||
archs: [arm64, x86_64] # target architectures (default: host)
|
||||
modes: [release, debug] # default: [release]
|
||||
output: bundles # optional output dir, relative to the workspace
|
||||
deps: # optional host packages, by OS / distro
|
||||
linux:
|
||||
fedora: [pkg-config, freetype-devel]
|
||||
ubuntu: [pkg-config, libfreetype-dev]
|
||||
macos: [pkg-config, freetype]
|
||||
windows: [Kitware.CMake]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `emb env`
|
||||
|
||||
Write `setup_env.sh` (`PATH` for Flutter/Dart, `FLUTTER_WORKSPACE`, `PUB_CACHE`,
|
||||
`XDG_CONFIG_HOME`, the engine version, …).
|
||||
|
||||
| Option | Default | Description |
|
||||
|---|---|---|
|
||||
| `-w`, `--workspace <dir>` | resolution order | Workspace root. |
|
||||
| `-o`, `--output <path>` | `<workspace>/setup_env.sh` | Output file path. |
|
||||
| `--print` | off | Print to stdout instead of writing a file. |
|
||||
|
||||
```sh
|
||||
emb env # write <workspace>/setup_env.sh
|
||||
emb env --print # preview on stdout
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `emb update`
|
||||
|
||||
Update the CLI itself (via `pub`). No options.
|
||||
|
||||
```sh
|
||||
emb update
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Modes
|
||||
|
||||
| `--mode` | How it builds | Bundle contents | Valid in |
|
||||
|-----------|---------------------------------------|-----------------|----------|
|
||||
| `debug` | JIT — `flutter build bundle --debug` | `kernel_blob.bin`, **no** `libapp.so` | `bundle`, `build`, `engine`, `setup` |
|
||||
| `profile` | AOT (`gen_snapshot`) | `libapp.so` (+ profile engine) | all |
|
||||
| `release` | AOT (`gen_snapshot`) | `libapp.so` (+ release engine) | all |
|
||||
|
||||
`emb aot` only accepts `release`/`profile` (debug isn't AOT). Where a command
|
||||
takes **multiple** modes (`aot`, `build`, `engine`, `setup`), repeat the flag:
|
||||
`--mode release --mode profile`. `emb bundle` takes a **single** mode.
|
||||
|
||||
A bundle is the directory ivi-homescreen consumes:
|
||||
|
||||
```
|
||||
<bundle>/
|
||||
data/flutter_assets/ # app code + assets
|
||||
data/icudtl.dat # from the engine
|
||||
lib/libflutter_engine.so # from the engine (per mode)
|
||||
lib/libapp.so # AOT image (profile/release only)
|
||||
```
|
||||
|
||||
### Modes
|
||||
|
||||
| `--mode` | how it builds | bundle contents |
|
||||
|-----------|---------------------------------------|------------------------------|
|
||||
| `debug` | JIT — `flutter build bundle --debug` | `kernel_blob.bin`, **no** `libapp.so` |
|
||||
| `profile` | AOT (`gen_snapshot`) | `libapp.so` (+ profile engine) |
|
||||
| `release` | AOT (`gen_snapshot`) | `libapp.so` (+ release engine) |
|
||||
|
||||
Defaults: **`--mode release`**, **`--arch` = host arch**. The engine SDK for the
|
||||
selected `(mode, arch)` is **fetched implicitly** if it isn't already cached, so
|
||||
you don't have to run `emb engine` first.
|
||||
|
||||
```sh
|
||||
emb bundle --app-path ./app/my_app --arch arm64 --build # release
|
||||
emb bundle --app-path ./app/my_app --arch arm64 --build --mode debug # JIT
|
||||
emb bundle --app-path ./app/my_app --arch riscv64 --build --mode profile
|
||||
emb bundle --app-path ./app/my_app --build # host (x86_64)
|
||||
emb bundle --app-path ./app/my_app --arch arm64 --out /tmp/bundle-out # custom path
|
||||
```
|
||||
|
||||
### Manifest-driven (`emb build`)
|
||||
|
||||
Give a package an `emb` manifest (an `emb.yaml`, or an `emb:` key in
|
||||
`pubspec.yaml`) so it builds itself with no flags:
|
||||
|
||||
```yaml
|
||||
# emb.yaml
|
||||
id: my_app
|
||||
type: app
|
||||
build:
|
||||
app_path: . # Flutter app dir, relative to this manifest
|
||||
archs: [arm64, x86_64] # target architectures (default: host)
|
||||
modes: [release, debug]# default: [release]
|
||||
output: bundles # optional output dir, relative to the workspace
|
||||
deps: # optional host packages, by OS / distro
|
||||
linux:
|
||||
fedora: [pkg-config, freetype-devel]
|
||||
ubuntu: [pkg-config, libfreetype-dev]
|
||||
```
|
||||
|
||||
```sh
|
||||
emb build ./app/my_app # builds the full arch × mode matrix
|
||||
emb build ./app/my_app --arch arm64 --mode release # override the matrix
|
||||
emb build ./app/my_app --no-build # assemble from existing artifacts only
|
||||
lib/libapp.so # AOT image (profile/release only)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cross-compiling
|
||||
## Architectures & cross-compiling
|
||||
|
||||
Cross-compile is **x86_64 host → target arch** (`arm64`, `riscv64`, …). The
|
||||
meta-flutter engine SDK ships a host-x86_64 **simulator** `gen_snapshot`
|
||||
(`linux_simarm64`) that emits target code and carries its own loader/libc in
|
||||
`clang_x64/lib64`, so it runs on any host glibc — **no qemu required**. `emb`
|
||||
selects and runs it automatically; `--gen-snapshot` / `--glibc-sysroot` override
|
||||
if you need to. Building **on** an arm64 host targets arm64 natively.
|
||||
`--arch` accepts machine names or Flutter tokens; they normalize to one of four
|
||||
**engine arch tokens** used in paths and bundle names:
|
||||
|
||||
---
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | What it does |
|
||||
| You pass | Normalized token |
|
||||
|---|---|
|
||||
| `emb doctor` | Host detection (os/arch/distro) + package-backend availability. |
|
||||
| `emb setup` | One-shot provision: deps → repos → Flutter SDK → engine, writes `setup_env.sh`. Phases are skippable (`--skip-deps`, …). |
|
||||
| `emb deps` | Coalesce host deps across manifests, filter to what's missing, install in one transaction. `--dry-run`, `--yes`. |
|
||||
| `emb sync` | Clone/update source repos into `<workspace>/app` (concurrent). |
|
||||
| `emb flutter` | Clone/checkout the Flutter SDK into `<workspace>/flutter`. |
|
||||
| `emb engine` | Fetch prebuilt engine artifacts for `--arch`/`--mode`. `--check` to test availability. |
|
||||
| `emb aot` | Build `libapp.so` (profile/release) for an app — the AOT primitive. |
|
||||
| `emb bundle` | Build (with `--build`) + assemble an ivi-homescreen bundle. |
|
||||
| `emb build` | Build a self-describing package (manifest `build:`) into bundles. |
|
||||
| `emb env` | Write `setup_env.sh` (`--print` to stdout). |
|
||||
| `x64`, `x86_64`, `amd64` | `x86_64` |
|
||||
| `arm64`, `aarch64` | `arm64` |
|
||||
| `arm`, `armv7`, `armv7hf`, `armhf` | `armv7hf` |
|
||||
| `riscv64` | `riscv64` |
|
||||
|
||||
Run `emb help <command>` for the full flag list.
|
||||
|
||||
---
|
||||
|
||||
## Workspace layout
|
||||
|
||||
```
|
||||
<workspace>/ # $FLUTTER_WORKSPACE
|
||||
app/ # cloned source repos
|
||||
flutter/ # Flutter SDK
|
||||
bundle/ # built bundles (default output)
|
||||
setup_env.sh # generated env
|
||||
.config/flutter_workspace/
|
||||
flutter-engine/<commit>/... # downloaded + extracted engine SDKs
|
||||
flutter-engine/bundle-<mode>-<arch>/ # staged engine halves
|
||||
```
|
||||
Cross-compile is **x86_64 host → target arch**. The meta-flutter engine SDK
|
||||
ships a host-x86_64 **simulator** `gen_snapshot` that emits target code and
|
||||
carries its own loader/libc in `clang_x64/lib64`, so it runs on any host glibc —
|
||||
**no qemu required**. `emb` selects and runs it automatically; `--gen-snapshot`
|
||||
/ `--glibc-sysroot` override if needed. Building **on** an arm64 host targets
|
||||
arm64 natively.
|
||||
|
||||
---
|
||||
|
||||
@@ -184,13 +406,14 @@ Run `emb help <command>` for the full flag list.
|
||||
|
||||
```sh
|
||||
dart pub get
|
||||
dart analyze # very_good_analysis
|
||||
dart analyze
|
||||
dart test
|
||||
```
|
||||
|
||||
> Note: the Linux PackageKit backend loads `packagekit_dart`'s native bridge.
|
||||
> `emb` locates it automatically; set `PK_NC_LIB=/path/to/libpackagekit_nc.so`
|
||||
> to override.
|
||||
The macOS/Windows package backends live in `lib/src/pkg/_platform/` and are
|
||||
excluded from the default (Linux) build — see that folder's `README.md`. Dart
|
||||
has no OS-conditional dependencies, so they're wired in only on per-OS builds
|
||||
that add `brew_dart` / `winget_dart`.
|
||||
|
||||
[license_badge]: https://img.shields.io/badge/license-Apache%202.0-blue.svg
|
||||
[license_link]: https://opensource.org/licenses/Apache-2.0
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
# emb examples
|
||||
|
||||
`emb` is a CLI. Install it, then run the commands below. See the
|
||||
[top-level README](../README.md) for the full command/flag reference.
|
||||
|
||||
```sh
|
||||
# from the package root
|
||||
dart pub get
|
||||
dart pub global activate --source=path . # puts `emb` on PATH
|
||||
# or run without activating: dart run bin/emb.dart <command>
|
||||
```
|
||||
|
||||
## 1. Inspect the host
|
||||
|
||||
```sh
|
||||
emb doctor
|
||||
```
|
||||
|
||||
```
|
||||
Host
|
||||
os: linux
|
||||
arch: x86_64 (flutter: x64, engine: x86_64)
|
||||
host type: fedora
|
||||
version: 43
|
||||
|
||||
Package backend
|
||||
selected: packagekit
|
||||
✓ packagekit is available
|
||||
```
|
||||
|
||||
## 2. Provision a workspace
|
||||
|
||||
Installs host dependencies (one transaction), clones repos, installs the
|
||||
Flutter SDK, and fetches the prebuilt engine — then writes `setup_env.sh`.
|
||||
|
||||
```sh
|
||||
emb setup --config ../configs --yes
|
||||
. ./setup_env.sh # Flutter/Dart on PATH, FLUTTER_WORKSPACE, …
|
||||
```
|
||||
|
||||
Run phases individually if you prefer: `emb deps`, `emb sync`, `emb flutter`,
|
||||
`emb engine`.
|
||||
|
||||
## 3. Build an ivi-homescreen bundle
|
||||
|
||||
```sh
|
||||
# Release AOT bundle for a Raspberry Pi (arm64), cross-compiled from x86_64:
|
||||
emb bundle --app-path ./app/my_app --arch arm64 --build
|
||||
|
||||
# Debug (JIT) bundle for the host:
|
||||
emb bundle --app-path ./app/my_app --mode debug --build
|
||||
```
|
||||
|
||||
The bundle directory (`data/flutter_assets`, `data/icudtl.dat`,
|
||||
`lib/libflutter_engine.so`, and `lib/libapp.so` for profile/release) is what
|
||||
ivi-homescreen runs:
|
||||
|
||||
```sh
|
||||
ivi-homescreen --b=<workspace>/bundle/my_app-release-arm64
|
||||
```
|
||||
|
||||
## 4. Self-describing packages
|
||||
|
||||
A package that ships an `emb.yaml` (or an `emb:` key in `pubspec.yaml`) builds
|
||||
itself with no flags:
|
||||
|
||||
```sh
|
||||
emb build ./app/my_app # builds the manifest's arch × mode matrix
|
||||
```
|
||||
+84
-16
@@ -4,37 +4,105 @@ import 'dart:isolate';
|
||||
import 'package:packagekit_dart/packagekit_dart.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
/// Best-effort: point `packagekit_dart`'s loader at the package's own prebuilt
|
||||
/// Best-effort: point `packagekit_dart`'s loader at a prebuilt
|
||||
/// `libpackagekit_nc.so` so the Linux backend works without the user having to
|
||||
/// export `PK_NC_LIB`.
|
||||
///
|
||||
/// The package's loader is synchronous and cannot resolve its own location, so
|
||||
/// we do it here (async) via [Isolate.resolvePackageUri] and hand the path to
|
||||
/// [setPackagekitLibraryPath] before the first `PkClient` use. No-ops on
|
||||
/// non-Linux hosts, when `PK_NC_LIB` is already set, or when the package can't
|
||||
/// be resolved (e.g. fully AOT-compiled) — in which case the loader's own
|
||||
/// we do it here (async) and hand the path to [setPackagekitLibraryPath] before
|
||||
/// the first `PkClient` use. Two layouts are handled:
|
||||
///
|
||||
/// 1. **Path / vendored dependency** — the `.so` sits in the package itself
|
||||
/// (`<pkg>/build/` or `<pkg>/native/_build/`), found via
|
||||
/// [Isolate.resolvePackageUri].
|
||||
/// 2. **Hosted (pub.dev) dependency** — the package dir in the pub cache is
|
||||
/// read-only, so the `package:hooks` build hook compiles the `.so` into the
|
||||
/// *consuming* project's `.dart_tool/hooks_runner/...` output instead. We
|
||||
/// locate it there.
|
||||
///
|
||||
/// No-ops on non-Linux hosts, when `PK_NC_LIB` is already set, or when nothing
|
||||
/// is found (e.g. a fully AOT-compiled binary) — in which case the loader's own
|
||||
/// env/next-to-exe/system fallbacks still apply.
|
||||
Future<void> configurePackageKitLibrary() async {
|
||||
if (!Platform.isLinux) return;
|
||||
if ((Platform.environment['PK_NC_LIB'] ?? '').isNotEmpty) return;
|
||||
try {
|
||||
// (1) The package's own prebuilt locations (path / vendored builds).
|
||||
final uri = await Isolate.resolvePackageUri(
|
||||
Uri.parse('package:packagekit_dart/packagekit_dart.dart'),
|
||||
);
|
||||
if (uri == null || !uri.isScheme('file')) return;
|
||||
// <pkg>/lib/packagekit_dart.dart → <pkg>
|
||||
final pkgRoot = p.dirname(p.dirname(uri.toFilePath()));
|
||||
final candidates = [
|
||||
p.join(pkgRoot, 'build', 'libpackagekit_nc.so'),
|
||||
p.join(pkgRoot, 'native', '_build', 'libpackagekit_nc.so'),
|
||||
];
|
||||
for (final c in candidates) {
|
||||
if (File(c).existsSync()) {
|
||||
setPackagekitLibraryPath(c);
|
||||
return;
|
||||
if (uri != null && uri.isScheme('file')) {
|
||||
// <pkg>/lib/packagekit_dart.dart → <pkg>
|
||||
final pkgRoot = p.dirname(p.dirname(uri.toFilePath()));
|
||||
for (final c in [
|
||||
p.join(pkgRoot, 'build', 'libpackagekit_nc.so'),
|
||||
p.join(pkgRoot, 'native', '_build', 'libpackagekit_nc.so'),
|
||||
]) {
|
||||
if (File(c).existsSync()) {
|
||||
setPackagekitLibraryPath(c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// (2) The build hook's output under the consuming project's .dart_tool.
|
||||
final hookBuilt = _findHookBuiltLibrary();
|
||||
if (hookBuilt != null) {
|
||||
setPackagekitLibraryPath(hookBuilt);
|
||||
return;
|
||||
}
|
||||
} on Object {
|
||||
// Best-effort only; fall through to the loader's other strategies.
|
||||
}
|
||||
}
|
||||
|
||||
/// Locate the `libpackagekit_nc.so` produced by the `package:hooks` build hook,
|
||||
/// which lands under `.dart_tool/hooks_runner/shared/packagekit_dart/build/
|
||||
/// <hash>/<cmake-build-dir>/libpackagekit_nc.so` in the consuming project.
|
||||
///
|
||||
/// Returns the most-recently-built match, or `null` if none is found.
|
||||
String? _findHookBuiltLibrary() {
|
||||
final dartTool = _locateDartTool();
|
||||
if (dartTool == null) return null;
|
||||
final buildRoot = Directory(
|
||||
p.join(dartTool, 'hooks_runner', 'shared', 'packagekit_dart', 'build'),
|
||||
);
|
||||
if (!buildRoot.existsSync()) return null;
|
||||
|
||||
File? best;
|
||||
// Layout is shallow: build/<hash>/<cmake-build-dir>/libpackagekit_nc.so.
|
||||
for (final hashDir in buildRoot.listSync().whereType<Directory>()) {
|
||||
for (final cmakeDir in hashDir.listSync().whereType<Directory>()) {
|
||||
final so = File(p.join(cmakeDir.path, 'libpackagekit_nc.so'));
|
||||
if (!so.existsSync()) continue;
|
||||
if (best == null ||
|
||||
so.statSync().modified.isAfter(best.statSync().modified)) {
|
||||
best = so;
|
||||
}
|
||||
}
|
||||
}
|
||||
return best?.path;
|
||||
}
|
||||
|
||||
/// Best-effort discovery of the consuming project's `.dart_tool` directory:
|
||||
/// prefer the running package config, else walk up from the current directory.
|
||||
String? _locateDartTool() {
|
||||
final pc = Platform.packageConfig;
|
||||
if (pc != null && pc.isNotEmpty) {
|
||||
final path = pc.startsWith('file:') ? Uri.parse(pc).toFilePath() : pc;
|
||||
// .../.dart_tool/package_config.json → .../.dart_tool
|
||||
final dir = p.dirname(path);
|
||||
if (p.basename(dir) == '.dart_tool' && Directory(dir).existsSync()) {
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
var dir = Directory.current;
|
||||
for (var i = 0; i < 8; i++) {
|
||||
final dartTool = p.join(dir.path, '.dart_tool');
|
||||
if (Directory(dartTool).existsSync()) return dartTool;
|
||||
final parent = dir.parent;
|
||||
if (parent.path == dir.path) break;
|
||||
dir = parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+2
-6
@@ -4,10 +4,7 @@ description: >-
|
||||
ivi-homescreen bundles (cross-compiled AOT for arm64/riscv64).
|
||||
version: 0.1.0
|
||||
repository: https://github.com/toyota-connected/emb_cli
|
||||
# Not published to pub.dev yet: depends on sibling packages via path.
|
||||
# To publish, see README/CHANGELOG — the path deps must become hosted.
|
||||
publish_to: none
|
||||
|
||||
issue_tracker: https://github.com/toyota-connected/emb_cli/issues
|
||||
|
||||
environment:
|
||||
sdk: ">=3.10.1 <4.0.0"
|
||||
@@ -21,8 +18,7 @@ dependencies:
|
||||
# backends live in lib/src/pkg/_platform/ and are wired in per-OS builds —
|
||||
# Dart has no OS-conditional dependencies, so depending on them here would
|
||||
# force them to compile on every platform. See lib/src/pkg/_platform/README.
|
||||
packagekit_dart:
|
||||
path: ../app/packagekit_dart
|
||||
packagekit_dart: ^0.3.2
|
||||
path: ^1.9.0
|
||||
pub_updater: ">=0.4.0 <0.6.0"
|
||||
yaml: ^3.1.0
|
||||
|
||||
Reference in New Issue
Block a user