perl: run on the default/unset locale without a startup panic (kd-dvph)#822
Conversation
The Perl bottle shipped only perl.wasm with no core-module runtime, and the interpreter crashed on any real module load, so the port only ever passed a trivial arithmetic smoke. Make Perl-on-Kandelo usable: File::Spec, POSIX, Cwd, XSLoader, Config and the pure-perl core all load and run. Fixes kd-k7zy (the kd-p3hr follow-up where File::Spec failed on missing generated XSLoader.pm). Three root causes, all in the build recipe: - Generated runtime files were never produced/packaged: `make perl` stops before perl-cross's nonxs/extensions targets that generate lib/XSLoader.pm and stage the core tree, and the target Config had an empty osname so MakeMaker's probes failed. Fix: -Dosname=linux + build with `make -k`, then package lib/perl5/5.40.3 as a new perl-runtime.zip output. - The interpreter miscompiled and panicked on any weak-ref use: -O2 without -fno-strict-aliasing miscompiles perl's weak-ref code into a magic_killbackrefs panic. The flag was on HOSTCFLAGS only; add it to the target -Dccflags. - XS core modules could not load: usedl=define builds .so's loaded via dlopen, which Kandelo wasm lacks. -Uusedl links XS into perl.wasm with a boot table so XSLoader::load resolves them without dlopen. perl-cross ignores -Dnoextensions, so the static set is curated by editing Makefile.config's fullpath_static_ext (drop ext/re, which duplicates core regcomp symbols, and external-lib/threads exts). Also work around a perl-cross bug where the static-ext recipe never runs pm_to_blib: after make -k, stage each curated static ext's .pm. build.toml revision 1 -> 2 (output bytes change). package.toml declares the perl-runtime output. Formula/perl.rb installs perl.wasm + the runtime and tests File::Spec/POSIX/XSLoader. demo/runtime-smoke.ts is a Node kernel-host smoke. Verified via Node runCentralizedProgram against the packaged perl-runtime.zip (LC_ALL=C): File::Spec catfile/rel2abs, Cwd, POSIX, Fcntl, List::Util, Data::Dumper, XSLoader, Config all load (PERL_RUNTIME_SMOKE_PASS). Known boundaries filed: kd-dvph (default-locale startup panic), kd-gtxa (Errno errno extraction), kd-14n8 (broaden static XS / dlopen). Browser bottle tracks kd-yuef. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
f0bf4f8 to
92022d4
Compare
Phase B-1 matrix build status —
|
| Package | Arch | Status | Sha |
|---|---|---|---|
| libcurl | wasm32 | built | b01be826 |
| libcxx | wasm32 | built | bd2dd5a6 |
| libcxx | wasm64 | built | 926cfc96 |
| libpng | wasm32 | built | 25e56ef0 |
| libxml2 | wasm32 | built | eb77d16a |
| libxml2 | wasm64 | built | 9743c3c9 |
| openssl | wasm32 | built | 296793ae |
| openssl | wasm64 | built | b53a16d9 |
| sqlite | wasm32 | built | 93b98c80 |
| sqlite | wasm64 | built | 7079a1ac |
| zlib | wasm32 | built | 4543740c |
| zlib | wasm64 | built | 4ccf5221 |
| bc | wasm32 | built | 0c54e287 |
| bzip2 | wasm32 | built | 614536d6 |
| coreutils | wasm32 | built | e1a33298 |
| curl | wasm32 | built | ecbc3967 |
| dash | wasm32 | built | 4f2caf8b |
| diffutils | wasm32 | built | 34f174f8 |
| dinit | wasm32 | built | 97a7849b |
| fbdoom | wasm32 | built | 3799bb5e |
| file | wasm32 | built | 535dd689 |
| findutils | wasm32 | built | 4b727dbf |
| gawk | wasm32 | built | 92e5184d |
| git | wasm32 | built | 42b4d1cb |
| grep | wasm32 | built | fd4d79fa |
| gzip | wasm32 | built | 8f54d8ac |
| kandelo-sdk | wasm32 | built | ba15af22 |
| kernel | wasm32 | built | 917959d2 |
| less | wasm32 | built | 7f3184f8 |
| lsof | wasm32 | built | 4dc5ae5b |
| m4 | wasm32 | built | 5fbbe8b3 |
| make | wasm32 | built | 57a6d854 |
| mariadb | wasm32 | built | 9ed4aa94 |
| mariadb | wasm64 | built | eaf29411 |
| modeset | wasm32 | built | d9f12284 |
| msmtpd | wasm32 | built | 23172a3a |
| nano | wasm32 | built | 763f56f8 |
| ncurses | wasm32 | built | a7862ee0 |
| netcat | wasm32 | built | 57bdd0cd |
| nginx | wasm32 | built | 933bdcd3 |
| php | wasm32 | built | e047ea3c |
| posix-utils-lite | wasm32 | built | 2aec933c |
| sed | wasm32 | built | 9d958a03 |
| spidermonkey | wasm32 | built | ef0ac7d5 |
| tar | wasm32 | built | 050e7cb3 |
| tcl | wasm32 | built | ee9ae67a |
| unzip | wasm32 | built | b176c19f |
| userspace | wasm32 | built | a9e013a2 |
| vim | wasm32 | built | 8194ff88 |
| wget | wasm32 | built | 378dca44 |
| xz | wasm32 | built | 763b854c |
| zip | wasm32 | built | 1c834314 |
| zstd | wasm32 | built | bcd693e5 |
| bash | wasm32 | built | d435c352 |
| mariadb-test | wasm32 | built | 74e71062 |
| mariadb-vfs | wasm32 | built | 85427981 |
| mariadb-vfs | wasm64 | built | 6c3ac528 |
| nethack | wasm32 | built | 5b7fc658 |
| node | wasm32 | built | cdad27ac |
| spidermonkey-node | wasm32 | built | 6d8dc738 |
| vim-browser-bundle | wasm32 | built | ef862c6f |
| nethack-browser-bundle | wasm32 | built | d4992e6b |
| rootfs | wasm32 | built | ae3df667 |
| shell | wasm32 | built | 61c3bb81 |
| lamp | wasm32 | built | f5445d80 |
| node-vfs | wasm32 | built | 75f6e69a |
| wordpress | wasm32 | built | 1c1bcff5 |
Auto-generated; replaced on each push. Raw data in the publish-status workflow artifact.
ext/Errno/Errno_pm.PL discovers the E* errno constants by preprocessing `#include <errno.h>` and scanning cpp output for `# <line> "file"` linemarkers. perl-cross defines cpp/cpprun/cppstdin as "$cc -E -P"; -P suppresses those linemarkers, so on the wasm cross target the scan found no headers, collected no constants, and Errno_pm.PL died "No error definitions found" -- Errno.pm was never generated/staged and `use Errno` failed. The constants are plain `#define E* <int>` in the sysroot (musl arch/generic bits/errno.h). build-perl.sh now patches get_files() to fall back to the sysroot errno headers when linemarker discovery yields nothing, adds Errno.pm to the fail-loud runtime post-check, and bumps the package revision (perl-runtime.zip now ships Errno.pm; perl.wasm is byte-unchanged). Adds Node + browser use-Errno smokes. Stacked on #821 (kd-k7zy). Verified: Node errno-smoke 16/16 (Errno.pm with 134 musl-valued constants + %! tie); browser smoke harness committed (skips where the browser bundle is absent; browser acceptance tracked by kd-yuef). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
musl's setlocale(LC_ALL,"") returns a positional ';'-separated composite
(e.g. "C.UTF-8;C;C;C;C;C") when the categories differ, but perl-cross
configured the wasm target with glibc's name=value assumption
(PERL_LC_ALL_USES_NAME_VALUE_PAIRS). perl parsed musl's first field
"C.UTF-8" as name=value, found no '=', and aborted at interpreter startup
(exit 29) for every locale except literally LC_ALL=C -- making perl unusable
with the default or any UTF-8 locale on Kandelo.
build-perl.sh now patches the target config.h to perl's positional LC_ALL
mode with musl's category order (CTYPE;NUMERIC;TIME;COLLATE;MONETARY;MESSAGES),
the mechanism perl already ships for *BSD; get_category_index() maps each
position to its internal index and a STATIC_ASSERT guards the count. Host
miniperl (xconfig.h) is left matching the build machine's libc. build.toml
revision 1->2 (output bytes change). Adds a Node + browser locale smoke and a
porting-guide troubleshooting note.
Verified on both kernel hosts: perl -e runs with an unset locale, LC_ALL=C,
LC_ALL=C.UTF-8, LANG=C.UTF-8, LANG=en_US.UTF-8, and a disparate composite
(all exit-29 panics before); built-in ${^UTF8LOCALE} confirms per-category
parsing routes CTYPE correctly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
92022d4 to
392e9c0
Compare
|
Re-stacked as part of the perl convoy. Base is now This PR's own change is the 5 locale files only: Note: the 'Files changed' tab may briefly show the whole stack (~10 files) — that's a base-change cache lag (the head was pushed just before the base was retargeted); it recomputes on its own and will retarget to |
Purpose
Perl on Kandelo aborted at interpreter startup for any locale except literally
LC_ALL=C, soperl -e 'print 2+3'panicked (exit 29) with the default/unset locale or any UTF-8 locale. This makes Perl usable on Kandelo with a normal environment. Fixes kd-dvph (blocks the homebrew-all umbrella kd-1mr).Root cause
Kandelo's libc is musl, whose
setlocale(LC_ALL, "")returns a positional,;-separated composite of the per-category locales in category order (CTYPE;NUMERIC;TIME;COLLATE;MONETARY;MESSAGES) when categories differ — e.g. with no locale env it returnsC.UTF-8;C;C;C;C;C. This is POSIX-legal (theLC_ALLreturn string is unspecified and need only round-trip throughsetlocale).perl-cross cross-configured the target with glibc's assumption (
d_perl_lc_all_uses_name_value_pairs=define), so perl compiled out its positional parser and parsed musl's first fieldC.UTF-8as a glibcname=valuepair. No=→locale.cpanic "needs an '=' to split name=value" → exit 29.This is a perl↔musl compatibility-boundary issue in the port config, not a platform gap: musl's format is POSIX-conformant, and forcing musl to emit glibc's format would change libc-wide behavior for every
setlocalecaller.Fix
build-perl.shpatches the targetconfig.h(the primary perl.wasm config; the build-time miniperl keepsxconfig.h) to perl's positionalLC_ALLmode — the mechanism perl already ships for *BSD:#undef PERL_LC_ALL_USES_NAME_VALUE_PAIRS#define PERL_LC_ALL_SEPARATOR ";"#define PERL_LC_ALL_CATEGORY_POSITIONS_INIT { LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_MESSAGES }(musl's emit order)get_category_index()maps each position to perl's internal index; a compile-timeSTATIC_ASSERTguards the count.build.tomlrevision 1 → 2 (output bytes change).Verification (both kernel hosts)
Node (
runCentralizedProgram+NodePlatformIO) — 8 pass / 0 fail / 1 skip; browser (headless Chromium viaBrowserKernel) — 2 pass / 0 fail.perl -enow runs with an unset locale,LC_ALL=C,LC_ALL=C.UTF-8,LANG=C.UTF-8,LANG=en_US.UTF-8(the browser default), and a disparate composite — all exit-29 panics before. Built-in${^UTF8LOCALE}confirms per-category parsing routes CTYPE correctly (not just non-panicking).New regression smokes:
packages/registry/perl/demo/locale-smoke.ts(Node) andlocale-browser-smoke.ts(browser). Docs: a porting-guide troubleshooting note on the musl-positional vs glibc-name=valueLC_ALLformat.Package-recipe-only change (build script + demo + docs); no kernel/host/musl/ABI code, so the 5-suite full gate is not triggered.
Coordination
Overlaps
build-perl.shwith the active perl-runtime work in #821 (kd-k7zy); this patch is orthogonal (startup locale scan vs module-loading) and small. Merge sequencing to be coordinated.🤖 Generated with Claude Code