Browse Source

make.tcl: warn when a kit .vfs folder has no startup script

New vfs_startup_script_warning check runs for each .vfs folder about to
be built against a runtime: it passes if the folder has a root main.tcl
or a root fauxlink resolving to the name main.tcl whose target exists
and is a .tcl file. Otherwise a noticeable warning is emitted and the
build proceeds (a kit with no startup script is legal).

Warnings use a new general-purpose ::punkboot::print_build_warnings
channel: column-0 BUILD-WARNING: token for greppability, ANSI highlight
for humans, and recap at end of run via the wrapped ::exit (same
treatment as PROVENANCE-WARNING). Overlay-only folders with no runtime
mapping (e.g _vfscommon.vfs) are not checked. Contract documented in
src/vfs/AGENTS.md.

Motivated by the punk9win.vfs split initially dropping the main.tcl
punk_main fauxlink from punk9wintk90b2.vfs.

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 1 week ago
parent
commit
a0cd2a982d
  1. 65
      src/make.tcl
  2. 1
      src/vfs/AGENTS.md

65
src/make.tcl

@ -1995,6 +1995,21 @@ proc ::punkboot::print_provenance_warnings {warninglines args} {
}
flush stderr
}
#General build warnings that must stay noticeable despite chatty build output - same
#column-0 greppable-token + recap-at-exit treatment as provenance warnings above.
set ::punkboot::build_warnings_pending [list]
proc ::punkboot::print_build_warnings {warninglines args} {
global A
if {![array size A]} {punkboot::define_global_ansi}
foreach w $warninglines {
regsub {^WARNING: } $w "" w
puts stderr "BUILD-WARNING: $A(BAD)$w$A(RST)"
if {"-norecap" ni $args} {
lappend ::punkboot::build_warnings_pending $w
}
}
flush stderr
}
#Availability probe + scoped dirty-src check, shared by the build/promotion gate below and the
#'check' command report. Returns {available warninglist}.
proc ::punkboot::get_src_provenance_warnings {projectroot label} {
@ -2019,6 +2034,11 @@ if {![llength [info commands ::punkboot::exit_original]]} {
puts stderr "PROVENANCE-WARNING: recap of warning(s) emitted earlier in this run:"
::punkboot::print_provenance_warnings $::punkboot::provenance_warnings_pending -norecap
}
if {[info exists ::punkboot::build_warnings_pending] && [llength $::punkboot::build_warnings_pending]} {
puts stderr ""
puts stderr "BUILD-WARNING: recap of warning(s) emitted earlier in this run:"
::punkboot::print_build_warnings $::punkboot::build_warnings_pending -norecap
}
::punkboot::exit_original $returnCode
}
}
@ -3835,6 +3855,43 @@ proc merge_over {sourcedir targetdir {depth 0}} {
$t destroy
puts stdout "\n${margin}merge vfs $sourcedir over $targetdir done."
}
#Startup-script presence check for a .vfs source folder about to be built into a kit.
#A kit's boot entry is a root-level main.tcl - either an actual file, or a root-level fauxlink
#resolving to the name main.tcl whose target exists and is a .tcl file (materialised into the
#build copy by the merge_over fauxlink handling above).
#Returns an empty string when a startup script is present, otherwise warning text.
#A kit without a startup script is legal (e.g a bare runtime + payload) - callers warn and
#continue rather than aborting.
proc vfs_startup_script_warning {vfsfolder} {
if {[file isfile [file join $vfsfolder main.tcl]]} {
return ""
}
package require fauxlink
set detail ""
foreach link [glob -nocomplain -dir $vfsfolder -types f *.fxlnk *.fauxlink] {
if {[catch {fauxlink::resolve $link} linkinfo]} {
append detail "; unresolvable fauxlink: [file tail $link]"
continue
}
if {[dict get $linkinfo name] ne "main.tcl"} {
continue
}
set linktarget [dict get $linkinfo targetpath]
if {[file pathtype $linktarget] eq "relative"} {
set linktarget [file join $vfsfolder $linktarget]
}
if {[file isfile $linktarget]} {
if {[string tolower [file extension $linktarget]] eq ".tcl"} {
return ""
}
append detail "; main.tcl fauxlink target '$linktarget' is not a .tcl file"
} else {
append detail "; main.tcl fauxlink target '$linktarget' does not exist"
}
}
return "vfs folder $vfsfolder has NO STARTUP SCRIPT: no root main.tcl and no root fauxlink resolving to main.tcl with an existing .tcl target - kits built from it will have no boot script (build proceeding anyway)$detail"
}
set startdir [pwd]
puts stdout "Found [llength $vfs_tails] .vfs folders - checking each for executables that may need to be built"
cd [file dirname $buildfolder]
@ -3904,6 +3961,14 @@ foreach vfstail $vfs_tails {
#assert $runtimes is a list of executable names suffixed with .exe if on windows - whether or not specified with .exe in the mapvfs.config
puts " vfs: $vfstail runtimes to process ([llength $runtimes]): $runtimes"
if {[llength $runtimes]} {
#only check startup script for .vfs folders that will actually be built against a runtime
#(e.g _vfscommon.vfs is a merge overlay with no runtime mapping and legitimately has no main.tcl)
set startup_warning [vfs_startup_script_warning $sourcefolder/vfs/$vfstail]
if {$startup_warning ne ""} {
::punkboot::print_build_warnings [list $startup_warning]
}
}
#todo - non kit based - zipkit?
# $runtimes may now include a dash entry "-" (from mapvfs.config file)
foreach runtime_fullname $runtimes {

1
src/vfs/AGENTS.md

@ -13,6 +13,7 @@ VFS (Virtual File System) folders define the runtime payloads that get wrapped i
## Local Contracts
- `*.vfs` folders are build artifacts consumed by `tclsh src/make.tcl project`.
- A `*.vfs` folder built against a runtime is expected to carry a root-level startup script: an actual `main.tcl`, or a root fauxlink resolving to the name `main.tcl` whose target exists and is a `.tcl` file. `make.tcl` warns when neither is present (column-0 `BUILD-WARNING:` token, ANSI-highlighted, recapped at end of run like provenance warnings) but still builds - a kit without a startup script is legal. Overlay-only folders with no runtime mapping (e.g `_vfscommon.vfs`) are not checked.
- VFS content must be compatible with the target platform runtime.
- `_vfscommon.vfs/` is an auto-generated merge of common libraries; manually editing it will be overwritten.
- `_config/punk_main.tcl` accepts an optional package_mode argument before the subcommand. Valid modes are `dev`, `os`, `internal`, and `src`, dash-delimited in priority order (e.g `src-internal`). `internal` is always appended if omitted.

Loading…
Cancel
Save