Documentation

whitehall build

Any source → an image in the store. The only verb that reads source.

Usage

whitehall build [source] [options]

source defaults to .. What comes out is an image, by name, in ~/.whitehall/images/ — not a file in your project. Every other verb takes that name. The .apk extension appears exactly once, at whitehall package, when a file has to cross to another phone.

What it accepts

A directory is classified by what is in it, most specific first. You do not pick a pipeline; build runs whatever compilers the directory calls for.

What's in the directoryWhat happens
[screen] in whitehall.tomlAn app: .wh → Kotlin → Gradle. Plus the NDK per ABI if [native] declares modules
Cargo.toml, go.mod, build.zig, CMakeLists.txtA tool: that language's own build runs inside the context, and the binary it produced becomes the image
main.pyA script, through the Python launcher
package.json + main.tsA Node program — no build step; node strips the types
[build] command in the manifestRun that instead of the detected build. For a lone main.c, which has no build system to read

It also takes a single .wh, .py or .ts file, and an ELF that is already cross-compiled.

[screen] is checked before Cargo.toml. A crate whose manifest declares a screen builds as an app, with the Rust linked in — that is what whitehall init --app inside a crate produces.

Options

FlagWhat it does
-r, --releaseOptimized build. Debug is the default, cargo's own
--name <name>Name the image something other than the source's own name
--no-cacheIgnore the build cache and rebuild every file
--no-compileSkip .wh → .kt; use the Kotlin already in build/
--wearBuild for Wear OS from src/wear/
--verifyBuild twice and diff the zip entries, to check the build is reproducible

Reproducible builds

--verify runs two builds of the same tree back to back, both forced past the build cache so both are real compiles, and names every zip entry that differs. Nothing should differ, so a difference is a finding.

$ whitehall build . --verify
   Building the first of two, to check reproducibility
   Building the second of two
   Differs: lib/arm64-v8a/libaimx.so
error: 1 zip entry differs between two builds of the same commit — not reproducible

Naming

The image is named for the directory — a project called Counter in examples/counter/ is counter in the store, because that is what you can see in a directory listing and therefore what you can type. name in the manifest is the label under the icon and nothing else. --name overrides.

What to do next

whitehall build .        # an image, by name
whitehall run counter    # start it, attached to its output
whitehall install counter  # put it on the phone, launchable by hand
whitehall package counter  # counter.apk, to hand to someone
whitehall images         # what's in the store

Those three verbs also take a path, so you rarely type the name twice. whitehall install . is build . piped into install, with the build's own cache deciding whether any work happens. A path-shaped argument means source; a bare word always means the store, so ./foo is how you mean the directory.

Iteration is not this verb

build is the shipping verb. The edit loop belongs to the language's own toolchain inside the context — cargo run, python3 main.py, go run ., node main.ts, zig build run — and to whitehall dev for an app, which has no other toolchain. There is no build --watch.

Transpile only

To read the Kotlin without producing an image:

whitehall compile

compile gates on the linter and refuses to emit when a rule reports an error. So does every verb that builds — build, run, install and dev — because they share one pipeline. To run just that gate, without generating anything, use whitehall check.

Environment files

Loaded in order, later overriding earlier:

Debug (default)Release
.env, .env.local, .env.debug, .env.debug.local.env, .env.local, .env.release, .env.release.local

See Also