Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions docs/porting-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,19 @@ headers from an arbitrary host LLVM install; the libcxx package generates and
ships a version-matched header tree with its `libc++.a` and `libc++abi.a`.
See `packages/registry/mariadb/build-mariadb.sh` for a complete example.

**Header-scanning build steps (cpp linemarkers + `-P`)**: Some language
runtimes discover constants at build time by preprocessing a system header and
scanning the output for `# <line> "file"` linemarkers to learn which headers to
grep (e.g. Perl's `ext/Errno/Errno_pm.PL` finds the `E*` errno constants this
way). perl-cross defines `cpp`/`cpprun`/`cppstdin` as `"$cc -E -P"`, and `-P`
*suppresses* linemarkers — so on the wasm cross target the scan discovers zero
headers and silently produces nothing (Errno then dies "No error definitions
found" and `use Errno` fails, even though the constants are plain `#define E*`
in `$WASM_POSIX_SYSROOT/include/bits/errno.h`). When a `.PL`/config step relies
on cpp linemarkers, point it at the sysroot header directly rather than
depending on linemarker discovery. See the `Errno_pm.PL` fallback patch in
`packages/registry/perl/build-perl.sh`.

### Step 3: Test it

```bash
Expand Down Expand Up @@ -819,3 +832,20 @@ accepted. See [fork-instrumentation.md](fork-instrumentation.md).
**Process hangs on read**: The fd might be in blocking mode waiting for data. Check that writers are properly closing their end of the pipe.

**Browser SharedArrayBuffer unavailable**: Ensure COOP/COEP headers are set. In production, the service worker handles this. In dev, Vite's config sets them.

**Locale panic / `setlocale(LC_ALL, "")` format mismatch**: 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 the categories differ —
e.g. with no locale env set it returns `C.UTF-8;C;C;C;C;C`. This is POSIX-legal
(the `LC_ALL` return string is unspecified and need only round-trip through
`setlocale`), but it is *not* glibc's `LC_CTYPE=…;LC_NUMERIC=…` `name=value`
form. A runtime that assumes the glibc format — often because a cross-build
tool defaulted to it — will mis-parse musl's output and can abort at startup.
Perl 5.40 hit exactly this: perl-cross configured the target with
`PERL_LC_ALL_USES_NAME_VALUE_PAIRS`, so perl parsed `C.UTF-8` as `name=value`,
found no `=`, and panicked (`packages/registry/perl/build-perl.sh` now patches
the target `config.h` to perl's positional mode with musl's category order; see
kd-dvph). If you port another locale-aware runtime and see startup failures
tied to `LC_ALL`, check whether it assumes the glibc composite format and point
it at musl's positional notation instead of forcing `LC_ALL=C`.
60 changes: 60 additions & 0 deletions homebrew/kandelo-homebrew/Formula/perl.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
require_relative "../Kandelo/formula_support/kandelo_package"

class Perl < Formula
include KandeloPackageFormula
SOURCE_URL = "https://www.cpan.org/src/5.0/perl-5.40.3.tar.gz"
SOURCE_SHA256 = "4c155b4e6160682b38919b55ac319081b898db11857cf18a7d9ffed2648ccaff"
PERL_PRIVLIB = "5.40.3"

desc "Perl interpreter for Kandelo (with generated core-module runtime)"
homepage "https://www.perl.org/"
url SOURCE_URL
sha256 SOURCE_SHA256
license any_of: ["Artistic-1.0-Perl", "GPL-1.0-or-later"]

skip_clean "bin"
skip_clean "lib/perl5"

def install
out_dir = kandelo_build_package("perl", "build-perl.sh", SOURCE_URL, SOURCE_SHA256,
script_env: { "PERL_VERSION" => version.to_s })
kandelo_install_bin(out_dir, "perl.wasm", "perl")

# Ship the generated core-module runtime library (XSLoader.pm, Config*.pm,
# File::Spec and the rest of the pure-perl core tree) so the runtime can
# load File::Spec (-> Cwd -> XSLoader); the bare perl.wasm carries none.
# build-perl.sh stages perl-src/lib via `make all` and zips it as
# perl-runtime.zip. The test's PERL5LIB (below) points at the installed
# lib/perl5/#{PERL_PRIVLIB}.
runtime_stage = buildpath/"perl-runtime-stage"
system "unzip", "-q", out_dir/"perl-runtime.zip", "-d", runtime_stage
(prefix/"lib").install Dir["#{runtime_stage}/lib/*"]
end

test do
# LC_ALL=C: perl 5.40 panics at startup parsing the composite default
# locale Kandelo's musl setlocale returns ('C.UTF-8;C;C;C;C;C') -- a
# separate platform boundary (kd-dvph), not this package's gap.
env = { "PERL5LIB" => (lib/"perl5/#{PERL_PRIVLIB}").to_s, "LC_ALL" => "C" }

# Interpreter smoke (the minimal strict/warnings arithmetic check).
assert_match "5", kandelo_run_wasm(bin/"perl",
["-e", "use strict; use warnings; print 2 + 3"], env: env)

# Regression guard for the reported gap (kd-k7zy): File::Spec must load and
# build the expected path, XSLoader.pm (the missing generated file) must
# load, and an XS core module must bootstrap through XSLoader::load.
prog = <<~PERL
use strict; use warnings;
use File::Spec;
use XSLoader;
use POSIX ();
my $p = File::Spec->catfile("a", "b", "c.txt");
die "File::Spec catfile: $p" unless $p eq "a/b/c.txt";
die "POSIX floor" unless POSIX::floor(3.7) == 3;
print "perl-runtime-ok xsloader=$XSLoader::VERSION";
PERL
assert_match "perl-runtime-ok xsloader=",
kandelo_run_wasm(bin/"perl", ["-e", prog], env: env)
end
end
Loading
Loading