diff --git a/goals/G-127-crosstarget-vfs-bake.md b/goals/G-127-crosstarget-vfs-bake.md index 557a5f89..8dfc50c5 100644 --- a/goals/G-127-crosstarget-vfs-bake.md +++ b/goals/G-127-crosstarget-vfs-bake.md @@ -197,3 +197,38 @@ exists locally (empty but for sha1sums.txt) and punkbin upstream carries non-native artifacts to bin/kits// (the same per-target wrap-seam composition question the G-057 icon note above records; bridge recorded from its side 2026-07-31, back-pointer added at the activation freshness survey). + +## Progress + +- 2026-07-31 increment 1 (output split, make.tcl): kit outputs are TARGET-keyed. + Kits for the host's default target keep the flat locations byte-identically + (punk86 rebake's deploy step skipped the install as content-identical to the + pre-change deployed kit); any other target's kit builds to + src/_build/kits// and deploys to bin/kits// with its own + per-tier bin .punkcheck ledger - the merged .vfs image, icon/resources sidecar, + arch scan, offset probe, smoke probe, release-gate and self-build guards all + follow the per-kit locations. The duplicate-name guard is per (target, name) in + BOTH the kit loop and the bakelist enumerator (mapvfs_kit_outputs), so + same-named kits for different targets coexist instead of being runtime-renamed + or overwritten; records gain out_tier; bakelist cross-target rows carry + out=kits// and the per-kit detail block prints the tiered + build/deploy paths (maketclplatform.test crosstarget pins updated to the new + surface - 5/5 pass; maketclbakelist.test untouched 9/9 pass). The kit-loop + cross-platform TODO is retired pointing here. LIVE: 'make.tcl bake punkshell902' + relocated the linux kit to bin/kits/linux-x86_64/punkshell902 (valid ELF, + sidecar beside it) - the INTENDED RELOCATION per Acceptance. The pre-move flat + copies (bin/punkshell902, src/_build/punkshell902 + .vfs image) remain as + orphans pending manual cleanup. CONSEQUENCE surfaced by the same rule: the + G-129 verification kits (punkluck86, punk91ix86 - target win32-ix86 is not the + host default win32-x86_64) will relocate to bin/kits/win32-ix86/ on their next + bake; their old flat bin copies become the same class of orphan. (G-129 + achieved - see goals/archive/G-129-kitboot-mountpoint-derivation.md; the kits + stay active per their mapvfs group description.) +- Remaining for acceptance: per-target payload declaration axis on the G-115 + .vfs.toml surface + punk9linux.vfs migrated-or-recorded; two-target one-vfs + characterization via the PUNK_MAPVFS_CONFIG seam (one-run distinct artifacts, + cross-run no-overwrite, two-non-native coexistence, mismatch-report regression + pin per the G-133 redundancy note); byte-comparability spot-check for a + zip-type native kit; existing punkexe suites pass as a set; bin/AGENTS.md + + src/AGENTS.md output-location docs; G-023 reconciliation statement recorded + here; punkshell902 + win32-ix86 relocation records finalized. diff --git a/src/make.tcl b/src/make.tcl index 25e97c3b..b0259b48 100644 --- a/src/make.tcl +++ b/src/make.tcl @@ -1166,8 +1166,10 @@ proc ::punkboot::lib::mapvfs_parse_config {mapfile rtbase sourcefolder default_t # TARGET .exe suffix, duplicate appname -> _) so listed names # match what a bake produces. Entries whose vfs folder is missing on disk never # reach the kit loop - they are appended after the buildable set so 'bakelist' -# can surface them as broken config. Duplicate-name disambiguation assumes the -# config keeps appnames unique (as the kit loop itself effectively does). +# can surface them as broken config. Duplicate-name disambiguation is per TARGET +# (G-127): same-named kits for different targets coexist under their own output +# tiers; a same-target duplicate assumes the config keeps appnames unique (as +# the kit loop itself effectively does). # $rtbase is the store ROOT (bin/runtime): each record resolves its own tier # under it, so entries targeting different platforms report their own store # presence (G-122). Returns a list of record dicts: @@ -1180,6 +1182,9 @@ proc ::punkboot::lib::mapvfs_parse_config {mapfile rtbase sourcefolder default_t # runtime_dir store tier folder holding the runtime ("" for "-") # target target platform (e.g win32-x86_64) # store_tier bin/runtime tier folder name for the target +# out_tier kit OUTPUT tier relative to bin/ and src/_build/ - "" for the +# default (host) target's flat locations, "kits/" for any +# other target (G-127) # vfs vfs folder tail (e.g punk9wintk903.vfs) # vfs_present 1|0 # smokerequire G-133 smoke-require package list as configured ("" when undeclared) @@ -1228,14 +1233,16 @@ proc ::punkboot::lib::mapvfs_kit_outputs {model rtbase sourcefolder} { set runtime_file $rtname[::punkboot::lib::platform_exe_suffix $target] set targetkit ${appname}[::punkboot::lib::platform_exe_suffix $target] set kitname $appname - if {$targetkit in $exe_names_seen} { - #duplicate appname configured - kit loop disambiguates the same way + if {[list $target $targetkit] in $exe_names_seen} { + #duplicate appname configured for the same target - kit loop + #disambiguates the same way (G-127: different-target namesakes + #coexist under their own kits// output tiers instead) set targetkit ${appname}_$rtname set kitname ${appname}_$rtname } set runtime_present [file exists [file join $runtime_dir $runtime_file]] } - lappend exe_names_seen $targetkit + lappend exe_names_seen [list $target $targetkit] lappend records [dict create\ kitname $kitname\ targetkit $targetkit\ @@ -1246,6 +1253,7 @@ proc ::punkboot::lib::mapvfs_kit_outputs {model rtbase sourcefolder} { runtime_dir $runtime_dir\ target $target\ store_tier $store_tier\ + out_tier [expr {$target eq $default_target ? {} : "kits/$target"}]\ vfs $vfstail\ vfs_present [file isdirectory [file join $sourcefolder vfs $vfstail]]\ smokerequire $smokerequires\ @@ -4690,7 +4698,14 @@ if {$::punkboot::command eq "bakelist"} { set kit_type [dict get $rec kit_type] set runtime [dict get $rec runtime] set vfstail [dict get $rec vfs] - set deployed [punkboot::lib::kit_deploy_state $buildfolder $binfolder [dict get $rec targetkit]] + #G-127: deploy-state roots follow the record's output tier (non-default + #targets live under kits// in both bin/ and src/_build/) + set out_tier [dict get $rec out_tier] + if {$out_tier eq ""} { + set deployed [punkboot::lib::kit_deploy_state $buildfolder $binfolder [dict get $rec targetkit]] + } else { + set deployed [punkboot::lib::kit_deploy_state $buildfolder/$out_tier $binfolder/$out_tier [dict get $rec targetkit]] + } set notes [list] if {$runtime ne "-" && ![dict get $rec runtime_present]} { lappend notes runtime=missing @@ -4702,6 +4717,8 @@ if {$::punkboot::command eq "bakelist"} { #cross-target entry: its runtime, store tier and artifact naming follow #its own platform, not this host's default lappend notes target=[dict get $rec target] + #G-127: and its build/deploy locations sit under the kits// tier + lappend notes out=$out_tier/ } if {[dict get $rec group] ne ""} { lappend notes group=[dict get $rec group] @@ -4784,8 +4801,9 @@ if {$::punkboot::command eq "bakelist"} { } elseif {![dict get $rec bake_default]} { puts stdout " bake_default: false (excluded from full bakes - bake by name to build)" } - puts stdout " build product: src/_build/[dict get $rec targetkit] [punkboot::lib::bakelist_file_detail $buildfolder/[dict get $rec targetkit]]" - puts stdout " deployed: bin/[dict get $rec targetkit] [punkboot::lib::bakelist_file_detail $binfolder/[dict get $rec targetkit]] state=[lindex $row 4]" + set relkit [expr {[dict get $rec out_tier] eq "" ? [dict get $rec targetkit] : "[dict get $rec out_tier]/[dict get $rec targetkit]"}] + puts stdout " build product: src/_build/$relkit [punkboot::lib::bakelist_file_detail $buildfolder/$relkit]" + puts stdout " deployed: bin/$relkit [punkboot::lib::bakelist_file_detail $binfolder/$relkit] state=[lindex $row 4]" } } exit 0 @@ -7949,14 +7967,17 @@ foreach vfstail $vfs_tails { set targetkit $appname.kit } else { set targetkit ${appname}$rt_suffix - if {$targetkit in $exe_names_seen} { - #duplicate appname configured? + if {[list $rt_target $targetkit] in $exe_names_seen} { + #duplicate appname configured for the SAME target? + #(G-127: same-named kits for DIFFERENT targets coexist under + #their own kits// output tiers - only a same-target + #duplicate needs a disambiguating name) #todo - consider creating as ${appname}(2) etc? - puts stderr "targetkit: $targetkit already seen - using name ${appname}_$rtname" + puts stderr "targetkit: $targetkit already seen for target $rt_target - using name ${appname}_$rtname" set targetkit ${appname}_$rtname } } - lappend exe_names_seen $targetkit + lappend exe_names_seen [list $rt_target $targetkit] lappend targetkits [list $targetkit $target_kit_type $kit_smokerequires $kit_attrs] } } @@ -7967,6 +7988,23 @@ foreach vfstail $vfs_tails { } puts stdout " processing targetkit: $targetkit_info" lassign $targetkit_info targetkit target_kit_type kit_smokerequires kit_attrs + #G-127: output locations are keyed by the kit's TARGET. Kits for this + #host's own default target keep the flat locations every launcher, test + #and habit expects (src/_build/, bin/); any other target's kit + #builds and deploys under a kits// tier so same-named kits for + #different targets coexist instead of overwriting each other across + #selective runs. bin/kits/ rather than bin// because + #bin/runtime// already means build INPUTS. + if {$rt_target eq $rt_default_target} { + set kit_builddir $buildfolder + set kit_deploydir $binfolder + set kit_relpath $targetkit ;#kit path relative to bin/ and src/_build/ + } else { + set kit_builddir $buildfolder/kits/$rt_target + set kit_deploydir $binfolder/kits/$rt_target + set kit_relpath kits/$rt_target/$targetkit + } + file mkdir $kit_builddir #G-024: bake_default=false entries (declared per entry or via their group) #are excluded from full bakes - explicit name/@group selection builds them. if {![llength $::punkboot::bake_selected_kitnames] @@ -7979,9 +8017,9 @@ foreach vfstail $vfs_tails { #created when absent, then replaced only by an explicit release step #(G-023 owns that step) - a normal bake never overwrites it. if {[dict exists $kit_attrs scheme_role] && [dict get $kit_attrs scheme_role] eq "release" - && [file exists $binfolder/$targetkit]} { - puts stdout " skipping $targetkit (release-gated scheme output: bin/$targetkit exists and a normal bake never overwrites it - the explicit release step is G-023; to force a rebuild now, delete bin/$targetkit first)" - lappend skipped_kits [list kit $targetkit reason "release-gated (bin/$targetkit exists)"] + && [file exists $kit_deploydir/$targetkit]} { + puts stdout " skipping $targetkit (release-gated scheme output: bin/$kit_relpath exists and a normal bake never overwrites it - the explicit release step is G-023; to force a rebuild now, delete bin/$kit_relpath first)" + lappend skipped_kits [list kit $targetkit reason "release-gated (bin/$kit_relpath exists)"] continue } #Self-build guard: never process the kit whose deployed executable is running this @@ -7991,7 +8029,7 @@ foreach vfstail $vfs_tails { #punk executable remains supported for everything except rebuilding that executable. #(a HOST filesystem comparison - case rules follow the host, not the target) set self_exe [file normalize [info nameofexecutable]] - set self_deploy_target [file normalize $binfolder/$targetkit] + set self_deploy_target [file normalize $kit_deploydir/$targetkit] if {$::punkboot::host_windows} { set is_self_build [string equal -nocase $self_exe $self_deploy_target] } else { @@ -8007,7 +8045,7 @@ foreach vfstail $vfs_tails { set vfs_installer [punkcheck::installtrack new $installername $basedir/.punkcheck] $vfs_installer set_source_target $sourcefolder $buildfolder set vfs_event [$vfs_installer start_event {-make-step build_vfs}] - $vfs_event targetset_init INSTALL $buildfolder/$targetkit + $vfs_event targetset_init INSTALL $kit_builddir/$targetkit set relvfs [punkcheck::lib::path_relative $basedir $sourcefolder/vfs/$vfstail] if {![dict exists $path_cksum_cache $relvfs]} { #e.g ../vfs/punk87.vfs {cksum xxxx cksum_all_opts {-cksum_content 1 ... -cksum_algorithm sha1}} @@ -8051,7 +8089,8 @@ foreach vfstail $vfs_tails { package require control #keep this a simple name - bin/punk script calls into src/_build/exename.vfs/main.tcl - set targetvfs $buildfolder/$targetkit.vfs + #(G-127: non-default-target kits keep the simple name under their kits// tier) + set targetvfs $kit_builddir/$targetkit.vfs file delete -force $targetvfs set extraction_done 0 @@ -8423,7 +8462,7 @@ foreach vfstail $vfs_tails { #the assemblers below consume wrap_runtime - the stamped per-kit copy #of the payload-free raw prefix when embedding happened, the untouched #raw prefix otherwise. Runtime store originals are never modified. - lassign [::punkboot::kit_icon_process $targetkit $rt_target $rtname $target_kit_type $sourcefolder $vfstail $raw_runtime $buildfolder] wrap_runtime kiticon_sidecar + lassign [::punkboot::kit_icon_process $targetkit $rt_target $rtname $target_kit_type $sourcefolder $vfstail $raw_runtime $kit_builddir] wrap_runtime kiticon_sidecar set wrapvfs $targetvfs switch -- $target_kit_type { @@ -8723,13 +8762,13 @@ foreach vfstail $vfs_tails { } } - if {[file exists $buildfolder/$targetkit]} { - puts stderr "deleting existing $buildfolder/$targetkit" + if {[file exists $kit_builddir/$targetkit]} { + puts stderr "deleting existing $kit_builddir/$targetkit" if {[catch { - file delete $buildfolder/$targetkit + file delete $kit_builddir/$targetkit } msg]} { - puts stderr "Failed to delete $buildfolder/$targetkit" - lappend failed_kits [list kit $targetkit reason "could not delete buildfolder kit at $buildfolder/$targetkit"] + puts stderr "Failed to delete $kit_builddir/$targetkit" + lappend failed_kits [list kit $targetkit reason "could not delete buildfolder kit at $kit_builddir/$targetkit"] $vfs_event targetset_end FAILED $vfs_event destroy $vfs_installer destroy @@ -8739,7 +8778,7 @@ foreach vfstail $vfs_tails { #WINDOWS filesystem 'tunnelling' (file replacement within 15secs) could cause targetkit to copy ctime & shortname metadata from previous file! #This is probably harmless - but worth being aware of. - file rename $buildfolder/$vfsname.new $buildfolder/$targetkit + file rename $buildfolder/$vfsname.new $kit_builddir/$targetkit # -- --- --- --- --- --- $vfs_event targetset_end OK @@ -8751,7 +8790,7 @@ foreach vfstail $vfs_tails { #deploys; plain/none (no attached zip - the metakit kit shape) and #unreadable results are silence. One EOCD scan + CD walk per #REBUILT kit only. - lassign [::punkboot::get_kit_offsetstyle_report $buildfolder/$targetkit] offprobe_available offprobe + lassign [::punkboot::get_kit_offsetstyle_report $kit_builddir/$targetkit] offprobe_available offprobe if {!$offprobe_available} { puts stderr "NOTE: kit offset-style pin unavailable (punkboot::utils kit_offsetstyle_report not loadable from bootsupport) - continuing without it" } elseif {[dict get $offprobe offsetstyle] eq "file"} { @@ -8771,7 +8810,7 @@ foreach vfstail $vfs_tails { puts stdout " smoke-require skipped for kit $targetkit: cross-target ($rt_target) - the artifact is not executable on this $::punkboot::host_platform host" } else { puts stdout " smoke-require probe for kit $targetkit (packages: $kit_smokerequires) - executing freshly built artifact via its tclsh subcommand" - ::punkboot::kit_smoke_require_probe $buildfolder/$targetkit $targetkit $kit_smokerequires + ::punkboot::kit_smoke_require_probe $kit_builddir/$targetkit $targetkit $kit_smokerequires } } @@ -8785,14 +8824,13 @@ foreach vfstail $vfs_tails { $vfs_event destroy $vfs_installer destroy - #TODO - allow building of kits for other platforms - # - we need to use /bin for only kits targetting current platform, - # and use /bin/ for others - # that we we can have same target executable for multiple platforms e.g executable just named 'punkshell' - # - to do this we need to change runtime/mapvfs.config to have platform names not just standalone target executable names - # (todo: change to toml format at same time) + #Cross-platform kit outputs: RETIRED TODO (G-127 - see + #goals/G-127-crosstarget-vfs-bake.md). Kits for this host's default + #target deploy flat to /bin exactly as always; any other + #target's kit deploys under /bin/kits// (the + #mapping side gained platform names + toml format under G-122/G-024). after 200 - set deployment_folder [file dirname $sourcefolder]/bin + set deployment_folder $kit_deploydir file mkdir $deployment_folder # -- ---------- @@ -8804,7 +8842,7 @@ foreach vfstail $vfs_tails { #set last_completion [$bin_event targetset_last_complete] $bin_event targetset_addsource $deployment_folder/$targetkit ;#add target as a source of metadata for change detection - $bin_event targetset_addsource $buildfolder/$targetkit + $bin_event targetset_addsource $kit_builddir/$targetkit $bin_event targetset_started # -- ---------- @@ -8827,16 +8865,16 @@ foreach vfstail $vfs_tails { } puts stdout "copying.." - puts stdout "$buildfolder/$targetkit" + puts stdout "$kit_builddir/$targetkit" puts stdout "to:" puts stdout "$deployment_folder/$targetkit" after 300 - file copy $buildfolder/$targetkit $deployment_folder/$targetkit + file copy $kit_builddir/$targetkit $deployment_folder/$targetkit #G-057: the kit resource sidecar ships with the kit - if {[file isfile $buildfolder/$targetkit.resources.toml]} { - file copy -force $buildfolder/$targetkit.resources.toml $deployment_folder/$targetkit.resources.toml + if {[file isfile $kit_builddir/$targetkit.resources.toml]} { + file copy -force $kit_builddir/$targetkit.resources.toml $deployment_folder/$targetkit.resources.toml } - lappend installed_kits $targetkit + lappend installed_kits $kit_relpath # -- ---------- $bin_event targetset_end OK # -- ---------- @@ -8847,7 +8885,7 @@ foreach vfstail $vfs_tails { #G-057: keep the deployed resource sidecar current even when the kit #itself is unchanged (the record can be newer than the kit rebuild - #e.g the sidecar feature arriving, or a host-capability change) - if {[::punkboot::kiticon::copy_ifchanged $buildfolder/$targetkit.resources.toml $deployment_folder/$targetkit.resources.toml] eq "copied"} { + if {[::punkboot::kiticon::copy_ifchanged $kit_builddir/$targetkit.resources.toml $deployment_folder/$targetkit.resources.toml] eq "copied"} { puts stdout " kit icon (G-057): refreshed deployed sidecar $deployment_folder/$targetkit.resources.toml" } lappend skipped_kit_installs [list kit $targetkit reason "no change detected"] diff --git a/src/tests/shell/testsuites/punkexe/maketclplatform.test b/src/tests/shell/testsuites/punkexe/maketclplatform.test index 7487f0a3..33fcc882 100644 --- a/src/tests/shell/testsuites/punkexe/maketclplatform.test +++ b/src/tests/shell/testsuites/punkexe/maketclplatform.test @@ -194,17 +194,18 @@ namespace eval ::testspace { } -result {timedout 0 exitcode 0 store 1 target 1 nonote 1} #added 2026-07-26 (agent, G-122) - test maketcl_bakelist_crosstarget_entry {a mapvfs entry declaring a non-default target lists with a target= note, resolves its own store tier and names a suffixless artifact} -constraints {punkexeavailable} -body { + test maketcl_bakelist_crosstarget_entry {a mapvfs entry declaring a non-default target lists with target= and out= notes, resolves its own store tier and names a suffixless artifact under its kits// tier} -constraints {punkexeavailable} -body { set r [maketcl_run {bakelist punkshell902}] set out [dict get $r output] set result [list] lappend result timedout [dict get $r timedout] exitcode [dict get $r exitcode] - lappend result row [regexp {(?n)^punkshell902\s+kit\s+tclkit-902-Linux64-intel-dyn\s+punk9linux\.vfs\s+\S+\s+target=linux-x86_64} $out] + lappend result row [regexp {(?n)^punkshell902\s+kit\s+tclkit-902-Linux64-intel-dyn\s+punk9linux\.vfs\s+\S+\s+target=linux-x86_64 out=kits/linux-x86_64/} $out] lappend result store [regexp {(?n)^\s+runtime file:\s+bin/runtime/linux-x86_64/tclkit-902-Linux64-intel-dyn \(present\)} $out] lappend result target [regexp {(?n)^\s+target:\s+linux-x86_64 \(declared in the kit mapping\)} $out] #linux target -> no .exe on the build product or the deployed artifact - lappend result nosuffix [regexp {(?n)^\s+build product: src/_build/punkshell902 } $out] - lappend result nosuffix2 [regexp {(?n)^\s+deployed:\s+bin/punkshell902 } $out] + #(G-127: a non-default-target kit's locations sit under the kits// tier) + lappend result nosuffix [regexp {(?n)^\s+build product: src/_build/kits/linux-x86_64/punkshell902 } $out] + lappend result nosuffix2 [regexp {(?n)^\s+deployed:\s+bin/kits/linux-x86_64/punkshell902 } $out] set result } -result {timedout 0 exitcode 0 row 1 store 1 target 1 nosuffix 1 nosuffix2 1}