Skip to content
This repository was archived by the owner on Jul 21, 2026. It is now read-only.

tcl: preserve the threaded language runtime - #41

Open
brandonpayton wants to merge 2 commits into
mainfrom
migrate/tcl-language
Open

tcl: preserve the threaded language runtime#41
brandonpayton wants to merge 2 commits into
mainfrom
migrate/tcl-language

Conversation

@brandonpayton

@brandonpayton brandonpayton commented Jul 11, 2026

Copy link
Copy Markdown
Member

Why

Kandelo users and downstream packages need the current Tcl 9 runtime from
Homebrew. The available package still comes from the older registry, and a
partial port could quietly fall back to Tcl 8.6 behavior or disable threads,
dynamic extensions, and child commands. Migrating the complete runtime matters
because those features exercise the real Kandelo threading, loader, filesystem,
and process contracts that Tcl applications depend on.

What changed

  • Build Tcl 9.0.1 through the Kandelo SDK with the tap-native zlib formula and target-derived Linux configure branches.
  • Use Tcl's portable threaded select notifier because its epoll backend additionally requires non-POSIX <sys/queue.h>.
  • Preserve load and pthread support; replace Tcl's native-only pthread entry-point cast with a typed adapter.
  • Install the normal runtime library, standard packages, tzdata, headers, static libraries, and build configuration.
  • Disable appended ZIPFS because trailing ZIP bytes are not valid in a strict Wasm module.
  • Instrument tclsh last and validate the final bytes as ABI-correct, genuinely fork-required, complete, non-Asyncify, and free of build/root/prefix/exact-zlib paths.
  • Exercise language, filesystem, packages, a real dynamically loaded C extension, real Tcl pthread create/join, and exec.

Exact source head

Base: c5705667a90b05754d2244a362f3f7fc95d2f9c3

Head: 632760bc250bf6c45157f9eb87fc5b2c2e10e498

Formula blob: d7835a01fa78a7c1e072e706afa9264d5753fad9

Formula SHA-256: fa16b11b7de5d316d1053b695a5fe66cba38fa4a08e7f069c1f33a3f5012f5e9

The two-commit shape is intentional:

  1. 527e7b20ba1ea01f95986e7c9df5053ed8555f0f is the content-preserving c570 restack of the accepted functional Formula; its range-diff change is only README insertion context.
  2. 632760bc250bf6c45157f9eb87fc5b2c2e10e498 is a contract-only repair: load support through installed-tap Tap.fetch, and replace the bespoke guard with kandelo_validate_wasm_artifact(tclsh, fork: :required, forbidden_paths: [zlib.to_s]).

No configure/build/install/test behavior changed in the contract commit, and no target-byte change is intended.

Exact-head static evidence

  • Ruby syntax passed.
  • The current shared support suite passed 37 runs / 279 assertions in the author validation.
  • Direct RuboCop style inspection found no offenses.
  • git diff --check, scope, and clean-worktree checks passed.
  • Independent exact-head review confirmed the shared loader/validator call provides real fork-import, continuation, ABI, inspection-tool, Asyncify, and forbidden-path enforcement.

A fresh exact-head Homebrew source build/test was not run because the isolated build prefix was occupied by another package lane. The historical ABI 18 bottle is not used as substitute exact-head evidence.

Historical functional evidence

The accepted functional Formula previously established:

  • exact source build passed with the complete Tcl runtime surface
  • full brew test passed when layered with #892, covering language/files/packages, a real side module, a real Tcl pthread create/join, and exec /bin/echo
  • historical local wasm32_kandelo bottle SHA-256 8126c749210815763722f28e680970ab00a4210f899ef07831e0bad4f7634dd8
  • installed tclsh was ABI 18, fork-complete, non-Asyncify, and free of host/private paths

That is historical functional evidence only. The bottle archive itself contains a Homebrew receipt source path, and no ABI 18 bottle is publishable after the consolidated ABI work.

Without #892, Tcl exposes a platform defect: its fork-child atfork callback restarts the notifier pthread, and the host misidentifies an unrelated export as __wasm_call_ctors, producing an invalid thread module. #892 uses authoritative linker evidence, validates the constructor signature, gates clone success on thread_ready, and rolls back failed launches in both Node and browser. This Formula does not patch around that runtime defect.

Source and final-byte gates

Source/platform merge waits on #873, #882, deterministic #888 on #889, and #892 after its post-#889 rebase/full rerun. #841 is unnecessary because the Formula uses a typed pthread adapter.

#842 and #874 are final-byte rebuild gates, followed by the consolidated ABI. They define final linked-output inputs even though they do not block source review.

#903 is not currently required because the historical 4.59 MB tclsh passed #882 extraction; final rebuilt bytes must still pass authoritative validation. #905 is unrelated because Tcl exercises direct fork/atfork, not posix_spawn parentage.

Publication gates

Publication order is #881 -> #887 -> #890 -> #885 plus tap #22. #887 supplies native Binaryen/WABT build-dependency prefixes; #895 supplies the clean /bin/echo Formula-test base; #890/#900 enforce that same-tap zlib is resolved and poured from its prior exact bottle with provenance.

Final sequence: land the ABI/toolchain stack; publish and pour exact zlib; build Tcl from that poured bottle under #900; publish Tcl; run literal stock Homebrew Node and Chromium pours.

This PR contains no bottle block, archive, sidecar, receipt, provenance metadata, Wasm artifact, platform change, or ABI change.

@brandonpayton
brandonpayton force-pushed the migrate/tcl-language branch from 3a91ed0 to 0ee8c6b Compare July 11, 2026 23:35
@brandonpayton
brandonpayton force-pushed the migrate/tcl-language branch from 0ee8c6b to 632760b Compare July 13, 2026 01:17
@brandonpayton

Copy link
Copy Markdown
Member Author

Independent exact-head re-review completed for 632760bc250bf6c45157f9eb87fc5b2c2e10e498: ACCEPT for force-push/source review; not merge/publish ready.

  • The separate contract commit changes only support loading and final artifact enforcement; functional build/install/test behavior is unchanged.
  • Installed-tap Tap.fetch and kandelo_validate_wasm_artifact(..., fork: :required, forbidden_paths: [zlib.to_s]) exactly resolve the two prior blockers.
  • The shared validator now fails closed on a real fork import, continuation exports, ABI/tool inspection, Asyncify, and embedded build/root/prefix/zlib paths.
  • Exact-head syntax/diff/clean checks pass; author validation also reports support 37/279 and style clean.
  • Historical source/test/bottle evidence remains functional evidence, not exact-head or final-ABI publication evidence.
  • Source gates: #873/#882/#888-on-#889/#892. Final-byte gates: #842/#874/consolidated ABI. Publication gates: #881/#887/#890/#885, tap ci: add thin tap workflows for bottle publishing and maintenance #22, #895, and #900 with zlib first.
  • #903 is not currently required; #905 is unrelated.

No Formula blocker remains. A clean source build/test and dependency-first final-ABI pours are still required before merge/publication.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant