10 KiB
G-127 Cross-target bake of a custom .vfs
Status: proposed Scope: src/make.tcl (target-keyed output location and deploy folder, kit-name disambiguation by target, payload/target mismatch reporting, retirement of the kit-loop cross-platform TODO); src/runtime/vendorlib_vfs.toml (per-target payload declaration - format coordinated with G-115 and G-024); src/runtime/mapvfs.config (one vfs definition paired with several targets); src/vfs/ (per-target payload convention with punk9linux.vfs as the migration case); bin/kits// (non-native kit output tier, beside the existing bin/runtime// input tier); src/tests/shell/testsuites/punkexe/ (characterization - two-target bake, no-collision, mismatch report); bin/AGENTS.md + src/AGENTS.md (where cross-target kits land) Goal: one kit definition bakes for several declared target platforms from a single source of truth - each target getting ITS binary payload and an output location that cannot be overwritten by another target's kit of the same name - so building a custom .vfs for this machine and for FreeBSD is a declaration, not a duplicated .vfs folder and a naming convention held in the developer's head. G-122 made the build read the right runtime for a target; this makes it write the right kit for one. Acceptance: two mapvfs entries pairing the SAME vfs definition with two different targets bake in one run to distinct artifacts - a native-target kit stays at bin/ exactly where it lands today, a non-native one at bin/kits// with src/_build separated the same way - and neither is overwritten when the two are baked as separate selective single-kit runs (the current defect: exe_names_seen resets per run, so the second write lands on the first); two NON-NATIVE targets sharing a kit name coexist as distinct artifacts, where today they collide or are disambiguated by runtime name rather than by platform; the binary payload installed into each target's kit is selected for that target from src/vendorlib_tcl/ through one declaration rather than by duplicating a .vfs folder per target, and a kit declared for a single target builds byte-comparably to today; a payload binary that would be LOADED on the kit's target but was built for another platform is reported naming the file and both platforms, while per-platform subdirectory layouts that the loader resolves correctly (e.g tcllib's //) are explicitly not flagged; bakelist shows each row's output location; the existing punk9linux.vfs is either migrated to the declaration or recorded here as deliberately staying hand-curated, and the linux punkshell902 kit's move from bin/ to bin/kits/linux-x86_64/ is recorded as an intended relocation; the G-023 reconciliation is stated (version-named outputs compose with the platform directory rather than competing with it); native win32 kit outputs are unchanged in name and location and the existing punkexe suites pass unchanged; the kit-loop TODO at src/make.tcl "allow building of kits for other platforms" is retired pointing here.
Context
G-122 (achieved - see goals/archive/G-122-host-target-platform-split.md) made the build
READ correctly for a target: which bin/runtime/<tier> a runtime comes from, its
filename suffix, the artifact's suffix, presence checks, process-sweep applicability. It
deliberately did not touch the output side. make.tcl still carries the standing TODO in
the kit loop, of which G-122 satisfied only the second half:
#TODO - allow building of kits for other platforms
# - we need to use <project>/bin for only kits targetting current platform,
# and use <project>/bin/<platform> for others
# that we we can have same target executable for multiple platforms
# - to do this we need to change runtime/mapvfs.config to have platform names <-- done
Three gaps remain, all measured 2026-07-26:
-
Output is flat.
src/_build/<name>andbin/<name>, no platform dimension.targetkit = <appname><suffix>and both linux-x86_64 and freebsd-x86_64 yield an empty suffix, so two POSIX targets of the same kit collide. Within one run the duplicate guard renames the second to<appname>_<runtimename>- RUNTIME-keyed, not platform-keyed. Across separate SELECTIVE runsexe_names_seenstarts empty, so the second simply overwrites the first in bothsrc/_buildandbin. win32-vs-posix is safe today only because of the.exesuffix - naming luck, not design, and the reason the linuxpunkshell902currently coexists withpunk91.exewithout trouble. -
The payload model is one hand-curated folder per target.
punk9linux.vfsIS the convention: a separate folder carrying linux.sofiles (tcllibc, tcltls, tdom, thread). It is not a vfslibs participant, so its lib tree is maintained by hand.vendorlib_vfs.tomlhardcodes the platform into the source path (source = "vendorlib_tcl9/win32-x86_64/tcludp1.0.13") with explicit per-vfs target lists - a shape inherited from G-037 (achieved 2026-07-08), which established "which vfs folders participate is explicitly declared per kit" back when there was only one target. So "bake the same custom .vfs here and on FreeBSD" is not expressible; you duplicate the folder and re-copy the pure-Tcl payload. Two mitigating facts:_vfscommon.vfs(merged into every kit) carries no platform binaries, so the common payload is already target-agnostic - the problem is confined to the kit-specific vfs. And leakage runs both ways:punk9linux.vfscurrently containstcllib2.0/md5c/win32-x86_64/md5c.dllandtcllib2.0/tcllibc/win32-x86_64/tcllibc.dll, harmless (the loader picks by platform dir) but dead weight from a wholesale tree copy. -
Nothing verifies payload against target. The cross-target
punkshell902bake produced a valid ELF, but the build would not have complained had that vfs been full of DLLs.
The runtime side is already in place for a FreeBSD experiment: bin/runtime/freebsd-x86_64/
exists locally (empty but for sha1sums.txt) and punkbin upstream carries
freebsd-x86_64/tclkit-851-freebsd7-x86_64, fetchable via
punk-runtime.cmd fetch -platform freebsd-x86_64.
Approach
- Adopt the developer's recorded split, with the directory named explicitly:
native-target kits stay at
bin/<name>(every launcher, test and habit expectsbin/punk91.exethere), non-native kits go tobin/kits/<platform>/<name>.bin/kits/rather thanbin/<platform>/becausebin/runtime/<platform>/already means build INPUTS - having outputs in a sibling shape one level up would read as the same thing. No ignore-rule work:/bin/*already coversbin/kits/(verified), so neither.gitignorenor the fossil ignore-glob needs a change. - Supply the PLATFORM AXIS to whatever payload-declaration mechanism exists at the time
(today
vendorlib_vfs.toml's explicit per-kit lists; G-115's toml if it lands first). This goal does not own the declaration FORMAT - it owns the requirement that a payload can be declared per target and selected by the kit's target. - Keep the mismatch check load-path-relevant: report a binary that would actually be LOADED on the target, and stay silent on per-platform subdirectory layouts the loader resolves correctly. A check that fires on every existing tree is noise, and the current trees have benign leakage.
Alternatives considered
- Put ALL kits under
bin/kits/<platform>/, including native - rejected: breaks every launcher, test, doc and habit that expectsbin/punk91.exe, for uniformity's sake. - Keep one .vfs folder per target and fix only the output collision - rejected: leaves in place exactly the duplication that motivates the goal.
- Make a payload/target mismatch a hard build failure - rejected as the DEFAULT: the current tree would fail immediately on known-benign leakage. Offer it as a strict flag.
- Disambiguate colliding names by runtime rather than by platform (extending today's
<appname>_<runtimename>behaviour) - rejected: it encodes the wrong axis, and it does nothing for the cross-run overwrite, which is the sharper half of the defect.
Notes
- Depends on: G-122 (achieved) - the input half; this is the output half of the same split, and retires the TODO that goal left standing.
- Related: G-115 - owns the payload DECLARATION FORMAT and is currently written without any platform axis (zero mentions of platform or target). Whichever of the two lands second adopts the other: this goal supplies the axis, that goal supplies the format.
- Related: G-023 - owns output NAMES and its Acceptance hardcodes
punk9-0.5.0.exe. This goal owns output LOCATION and the suffix; the two must compose (bin/kits/<platform>/punk9-0.5.0) rather than compete. - Related: G-114 - the same platform axis one layer down (per-platform tm module roots registered by the boot for the running platform). A cross-target kit's tm roots must be the TARGET's. Note the xref shows G-114 and G-115 unlinked despite overlapping: the platform axis and the payload axis have never been connected, and this goal is that connection.
- Related: G-024 - format home for expressing one vfs definition against several targets.
- Related: G-057 - icon embedding is a windows-target-only wrap step keyed off a per-vfs override, so "which kits get an icon" becomes a target question once one vfs definition serves several targets. Settled there 2026-07-26: the override is shared across a kit definition's targets and carries no target dimension - used where embedding applies, ignored elsewhere.
- Related: G-105 - produces the cross-target RUNTIMES this consumes for custom kits.
- Related: G-005 / G-006 - where a target's binary payload comes from: built from source or downloaded with consent.
- Related: G-116 / G-020 - concrete per-platform binary payloads inside kit vfs lib trees (suite-built tcltls; the screen-capture backends under punk9wintk903.vfs/lib_tcl9).
- Related: G-101 - 8.6 containers ride the same mapping and output surfaces.
- Related: G-037 (achieved 2026-07-08) - established the per-kit declared vfslibs propagation whose single-target assumption this goal generalizes; see goals/archive/G-037-vendorlib-vfs-propagation.md.
- Tension to hold in view: G-004 (no committed binaries) - per-target payloads multiply the binary count in the tree unless they arrive by build or fetch.