update docs

This commit is contained in:
2026-09-22 13:23:34 +08:00
parent 99bc3d15c5
commit 8a4788fca8
126 changed files with 7198 additions and 2425 deletions
+315
View File
@@ -0,0 +1,315 @@
# Working on FDS/OS
Development reference and historical context. For current operating instructions, use the [user manual](../README.md). Acceptance applies only to the source and artifacts identified in each record.
[Documentation index](README.md) · [First build](getting-started.md) · [Troubleshooting](troubleshooting.md)
This guide is for someone who has completed the first build and wants to change
or inspect the working code. Run commands from the repository root, as a normal
user. M0–M12 software acceptance is complete; consult [AGENTS.md](../../AGENTS.md)
and the [roadmap](roadmap.md) before adding components.
## Choose the smallest useful build
| You changed or want to do | Run |
| --- | --- |
| See the available entry points | `make help` |
| Prepare a new checkout or restore missing host tools | `make bootstrap` |
| Edit the Rust smoketest | The Rust build and validation sequence below |
| Build/test the base display controller | `make dasung`, then `make dasung-test`; see [Dasung](dasung.md) |
| Change the CLI, shared contracts or stage0 | `make tooling`, then `make tooling-test`; rebuild initramfs and run `make boot-test` for boot-path changes |
| Change kernel configuration | `make kernel`, rebuild rootfs and boot images, then `make boot-test`; see [Boot images](boot.md) |
| Change USB discovery, mapping or media writing | Build CLI images, then `make stress-test`; see [Stress tests](stress-testing.md) |
| Change shutdown or DATA safety | Rebuild both profiles; run `make power-test` against development, plus `make data-test` and `make init-test`; see [Shutdown](power.md) |
| Change init or boot services | `make rootfs PROFILE=cli`, `make rootfs-test`, then `make init-test`; see [Native init](init.md) |
| Change base packages or rootfs assembly | `make rootfs PROFILE=cli`, `make rootfs-test`, then `make init-test`; see [Rootfs](rootfs.md) |
| Build the native development toolset | `make rootfs PROFILE=development`, `make rootfs-test`, `make system-card PROFILE=development`, then `make development-test` |
| Change internal storage or machine settings | Rebuild CLI and recovery, then `make internal-test`; see [Internal storage](internal-storage.md) |
| Change release signing or verification | `make signing-test`; see [Release signatures](releases.md) |
| Rebuild the test XBPS package | `./tools/build-package hello` |
| Verify an M0 build-system change | `make bootstrap`, then `make smoke-test`, then `make check` |
| Check Rust formatting and validation protections | `make check`, after building the Rust program |
| Read or edit documentation | Check examples, links, and claims against the implementation |
Run builds sequentially. The scripts share one Void masterdir and package cache;
starting bootstrap and package builds concurrently is not a supported workflow.
`make packages` builds every FDS base package. `make all` builds the complete
artifact set; two independent frozen offline builds passed with matching output. See
[Frozen inputs and offline rebuilds](reproducible-builds.md). Use `make clean-preview`
and `make clean` to remove obsolete workspaces and Rust compilation output while
keeping published images, latest test fixtures, saved releases, inputs and
caches. See [Cleanup](cleanup.md) for retention rules and rebuilding afterward.
There is no generic `make test` target.
## Edit and rebuild the Rust program
The active program is [rust/fds-smoketest/src/main.rs](../../rust/fds-smoketest/src/main.rs).
It is deliberately tiny: it establishes that the intended target and static
linking work. `rust/dasungd/`, `rust/fds-common/`, `rust/fds-cli/`, and
`rust/fds-stage0/`, `rust/fds-boottrace/`, and `rust/fds-cartridged/` are also active. Directories absent from the workspace member
list remain reserved. Use the [tooling guide](tooling.md) for the FDS programs,
[Cartridges](cartridges.md) for bay and metadata changes, and [DATA](data.md)
for writable storage and managed jobs.
Use the shared `clap` workspace dependency for every Rust command-line interface.
Declare commands and options with `Parser`, `Subcommand`, `Args`, and typed value
parsers; do not match or consume raw argument vectors. Shared media syntax lives
in `rust/fds-burn/src/cli.rs`; installed FDS aliases use Clap's multicall support
in `rust/fds-cli/src/cli.rs`. Keep authorization and filesystem validation in the
operation layer after parsing. Add parser tests when changing required options,
conflicts, private s6 flags, aliases, or child-argument forwarding.
The disposable Rust VM workloads in `tests/helpers/` are a Cargo workspace
member and use the same locked Clap dependency. They are never installed in
the base packages. Their stress workload uses release optimization level 2;
production executables retain the size-oriented release settings.
After editing the program:
```sh
cargo fmt --all
cargo build --locked --offline --release \
--target aarch64-unknown-linux-musl -p fds-smoketest
./tools/verify-elf target/aarch64-unknown-linux-musl/release/fds-smoketest aarch64 static
make check
```
Cargo writes to `target/aarch64-unknown-linux-musl/release/`. It does **not** refresh
`out/fds-smoketest` or its manifest. Run `make smoke-test` when you need a freshly
exported artifact and matching checksums.
If you installed optional QEMU, execute the freshly built file with:
```sh
qemu-aarch64 target/aarch64-unknown-linux-musl/release/fds-smoketest
```
The smoke-test contract expects exactly `FDS/OS M0: aarch64 static-musl OK`.
Changing that text requires updating the runtime assertion and documentation as
part of the same change. The crate also rejects the wrong architecture, libc,
or missing static CRT at compile time. Do not bypass those checks to make an
x86_64 build appear to pass.
The release profile and target configuration live in [Cargo.toml](../../Cargo.toml)
and [.cargo/config.toml](../../.cargo/config.toml). Rust and target versions are
selected through [rust-toolchain.toml](../../rust-toolchain.toml). This M0 crate has
no external crate dependencies. `--offline` works after bootstrap has installed
the toolchain; it is not a promise that the complete build pipeline is offline.
## Build and inspect a package
```sh
./tools/build-package hello
```
This checks the Void source pin, prepares configuration and overlays, invokes
xbps-src's aarch64 cross build, and copies the resulting main package into
`out/packages/`. Its log is `out/logs/xbps-hello.log`. Follow
[Packages](packages.md) for indexing, querying, and extracting the output.
`hello` is the verified M0 package. The helper accepts other template names, but
its exporter currently looks only for that main package in the top-level
`hostdir/binpkgs/`. Packages emitted into subrepositories and separately named
subpackages need additional handling; the helper is not yet a universal package
export interface.
For diagnosis, this is the underlying command in its correct host environment:
```sh
(
export PATH="$PWD/.host/xbps/usr/bin:$PATH"
export XBPS_ARCH=x86_64
cd vendor/void-packages
./xbps-src -a aarch64 pkg hello
)
```
The subshell keeps the directory and environment changes local. Prefer the FDS
helper for normal work: it also checks the pin and exports the output. The raw
command does neither. Do not run `xbps-install` against the Arch host or install
an ARM package into the x86_64 build container.
## Change build configuration deliberately
The source of truth is [config/xbps-src.conf](../../config/xbps-src.conf).
`XBPS_MAKEJOBS` controls package build parallelism; the current value is 4.
`XBPS_CHROOT_CMD=bwrap` selects the supported container backend.
`tools/prepare-void` copies this file to the ignored
`vendor/void-packages/etc/conf`. If the two differ, it stops instead of silently
overwriting local settings. After intentionally editing the checked-in file,
review the difference:
```sh
diff -u vendor/void-packages/etc/conf config/xbps-src.conf
```
A difference makes `diff` exit 1; that is expected. Once the checked-in version
contains every setting you intend to keep, synchronize and prepare:
```sh
cp config/xbps-src.conf vendor/void-packages/etc/conf
./tools/prepare-void
```
This overwrites the local generated configuration, so reconcile any intentional
local edits before copying. Re-run the three M0 validation commands after a build
configuration change. A mirror change does not lock the packages served by that
mirror; see [input limitations](build-host.md#known-limitations).
## How future package overlays fit
FDS-owned package sources belong in `packages/fds-*/`, outside the upstream
submodule. An overlay becomes active only when its directory contains a
`template`. `fds-base`, `fds-base-files`, `fds-init`, `fds-dasungd`, `fds-cli`, `fds-kernel`,
`fds-cartridged`, `fds-eink`, and `fds-dhcpcd` are active.
For active overlays and future templates, `tools/prepare-void` copies each
active directory into `vendor/void-packages/srcpkgs/`. It allows an identical
repeat copy, rejects a name that collides with a tracked upstream package, and
stops if a previous generated copy differs. Edit the source under `packages/`,
then reconcile the specific stale generated copy. Never put the only copy of an
FDS change inside `vendor/`.
The [troubleshooting guide](troubleshooting.md#configuration-or-overlay-conflict)
explains how to preserve and inspect a conflicting copy. Empty future directories
are intentional; adding a fake template to silence a missing-package error does
not implement that milestone.
## Preserve logs and identify inputs
The normal log filenames are reused. Before reproducing a failure that you need
to retain, save the existing logs:
```sh
log_archive=$(mktemp -d "$PWD/out/saved-logs.XXXXXX")
cp -a out/logs/. "$log_archive/"
printf 'Saved logs to %s\n' "$log_archive"
```
After a successful smoke-test:
```sh
cat VOID_PACKAGES_COMMIT
rustc --version
cargo --version
cat out/manifests/void-build-packages.txt
sha256sum -c out/manifests/artifacts.sha256
```
The package inventory lists what remains installed in the build container after
xbps-src cleans up temporary dependencies. Cached package digests and build logs
provide additional input records. These records do not constitute a complete,
immutable upstream package repository snapshot.
## Source updates and changes for review
Keep upstream tracked files unchanged. Updating Void is a deliberate change to
both the submodule gitlink and `VOID_PACKAGES_COMMIT`, followed by the full M0
checks. Updating host XBPS requires a matching archive URL and checksum. Updating
Rust requires considering the pinned toolchain, target, and generated artifacts
together. Do not use an unreviewed `git pull` inside the submodule as a repair.
For a change report, state what changed, which commands actually passed, and what
was skipped. Include the failing command and relevant log when reporting a bug.
Do not describe ELF inspection as execution, QEMU userspace execution as a Pi
boot, or a target timing as a measured result. Use English for documentation,
comments, diagnostics, and project discussions.
## Desktop verification
Build `make rootfs PROFILE=development`, then run `make desktop-test`. This
executes the actual ARM WindowMaker, terminal, cartridge daemon, and DHCP client
in disposable VMs. Its Xvfb backend and root test console exist only in generated
fixtures. The normal SYSTEM configuration uses Xorg and the ordinary FDS user.
VM helpers place QEMU in a private network namespace. The test's virtual DHCP
server can advertise DNS while remaining unable to reach host interfaces or the
Internet. QEMU diagnostics have separate `*.stderr.log` files, keeping host
emulator messages out of guest serial/JSON responses. Screenshots and measured
activation timestamps are retained under `out/m8-vm.*`.
To return to a console image after desktop development, rebuild
`make rootfs PROFILE=cli` and `make system-card PROFILE=cli`. A SYSTEM image cannot
be relabeled as another profile without rebuilding the matching filesystem.
## Use the development SYSTEM
`profiles/development.list` extends the same immutable base with native aarch64
**glibc** development tools. FDS control programs retain their static-musl build.
Build and verify the profile on the x86_64 workstation:
```sh
make rootfs PROFILE=development
make rootfs-test
make system-card PROFILE=development
make development-test
```
These commands do not install compilers on the Pi's read-only SYSTEM at runtime.
The profile must be built into a new SYSTEM image. Store source code and build
outputs on an active DATA cartridge, or under `/tmp` for disposable experiments.
The ordinary user's home is temporary in this profile too.
At native startup, FDS advances an older wall clock to the image's fixed source
timestamp in `/usr/share/fds/build-epoch`. A newer kernel/RTC clock is retained.
This prevents immutable compiler and CMake inputs from appearing to be in the
future when a machine boots without a usable RTC. It requires no network,
time server or waiting. `/run/fds/clock.json` records which case occurred.
The floor is an approximate lower bound, **not the current date**. Set the date
explicitly from a trusted time source when accurate timestamps or certificate
validity matter. Physical Pi RTC behavior remains to be tested. Boot-duration
measurements continue to use `CLOCK_BOOTTIME`, independent of wall-clock changes.
`make development-test` checks the older-clock case while compiling real projects;
`make clock-test` checks preservation of a newer clock in a disposable VM.
| Selected package(s) | Purpose |
| --- | --- |
| `gcc`, `glibc-devel` | Native C/C++ compilation, libc headers and startup files; GCC selects its matching support libraries and C++ headers |
| `make`, `cmake`, `meson`, `ninja`, `pkg-config` | Common project build systems and dependency discovery; Meson brings its Python runtime |
| `rust`, `cargo` | Native Rust development and package builds; Rust selects its standard library and LLVM runtime dependencies |
| `git` | Local source history and optional remote checkout when networking is explicitly enabled |
| `gdb`, `strace` | Interactive debugging and syscall inspection |
| `vim` | Terminal editing, with no graphical session required |
| Xvfb and the existing X11 diagnostic tools | Virtual desktop integration tests; they remain opt-in |
No development package is added to the boot service bundle. The profile uses
GCC for C/C++ and Rust for Rust; additional compilers and physical performance
profilers can be considered separately when there is a concrete need.
For a disposable first C program at `FDS>`:
```sh
mkdir -p /tmp/hello
cd /tmp/hello
printf '#include <stdio.h>\nint main(void) { puts("Hello from FDS"); }\n' >hello.c
cc -g -o hello hello.c
./hello
gdb ./hello
```
Within GDB, use `break main`, `run`, `next`, and `quit`. For persistent work,
use `/data/projects` after selecting a healthy DATA cartridge. Stop programs and
leave that directory before `fds eject BAY`.
For a dependency-free Rust example:
```sh
cargo new --vcs none /tmp/hello-rust
cd /tmp/hello-rust
cargo run --offline
```
`--offline` avoids contacting a registry. Projects with third-party crates need
those sources prepared beforehand or an explicit network connection. To preserve
Cargo downloads, put `CARGO_HOME` on DATA and stop related builds before ejecting.
An ordinary development program uses the target's glibc environment; rebuilding
the FDS distribution and its static control plane still follows the documented
x86_64 cross-build workflow.
`make development-test` runs native C, C++ and Rust compiler/linker executions,
CMake/Meson/Ninja/Make builds, GDB and strace, a local Git commit, and a headless Vim
edit in a disposable ARM VM. It verifies read-only SYSTEM, absent optional
services and native shutdown. Test results are recorded in
[M12 validation](m12-validation.md); they do not establish Pi compiler throughput.