lib: extract rt module from os, sweep imports

Hare puts runtime allocation in rt::, not os:: (ref/hare/rt/malloc.ha:27,
README). ww's `@symbol("rt_alloc") fn alloc(n: u64) *void;` lived at
lib/os/os.ww as a historical bootstrap shortcut; this commit relocates
it to a new lib/rt/malloc.ww and sweeps every site that depended on
`import os` for the alloc decl over to `import rt`.

This is commit 1 of 3 in the lib/rt extraction (#35):
  1. (this) move decl, sweep imports — preserves shape
  2. rename rt_alloc → rt_malloc (#38)
  3. nullable return type + OOM-propagating builtin lowering (#39)

No rename here. Symbol stays rt_alloc, function stays `alloc`, return
stays *void. Behavior identical — same ffi resolution outcome, just
sourced from a different module file. The rt::ensure runtime helper at
selfhost/rt/ensure.ww is its own compilation unit with a local decl and
is untouched.

Side effect: every wcc cgen file used `rt` as a local *node variable
name for "return type." `import rt;` shadows the module, so each
selfhost/cmd/wcc/{check,cgenstmt,cgenexpr,cgenutil}.ww site renamed
to `rtyp`. Mechanical follow-through; only the wcc module-import was
forced to do this rename.

Verified 132/132 + 995_self_rebuild byte-identity (5 wwstage tools
round-trip byte-identical).
This commit is contained in:
2026-05-20 20:39:52 +09:00
parent a1ee817906
commit d68d3c7eb4
34 changed files with 530 additions and 488 deletions

View File

@@ -110,28 +110,6 @@ import time;
@symbol("rt_syscall") fn syscall3(num: nr, a: i64, b: i64, c: i64) i64;
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
// alloc / free — runtime mmap-backed page allocator. Untyped:
// `alloc(n)` returns a `*void` and `free(p, n)` requires the byte
// count back because rt_free is munmap-based and doesn't track
// mapping sizes (the kernel needs the length to release the
// reservation).
//
// Diverges from Hare. Hare exposes `alloc` / `free` as typed
// language builtins (`alloc(value, cap)?` / `free(ptr)`) that the
// compiler lowers to rt::malloc/rt::free; ww has no such builtins,
// so the rt-symbol surface is exposed directly. Stdlib callers
// that need a typed allocation pattern wrap this with a cast plus
// a stored capacity (see [[strings.dup]], [[memio.dynamic]]).
//
// OOM: rt_alloc is a bare mmap(MAP_ANON|MAP_PRIVATE) wrapper with
// no error path. The raw Linux mmap syscall returns a negative
// errno cast to `*void` on failure (e.g. `(void*)-12` for ENOMEM);
// the `MAP_FAILED` (`(void*)-1`) value is a libc-wrapper convention
// that rt_alloc doesn't apply. Neither `== nil` nor `== (void*)-1`
// catches it; any deref of such a return faults. Today the stdlib
// does not check; OOM faults on first dereference. A typed
// fallible variant is a future task.
@symbol("rt_alloc") export fn alloc(n: u64) *void;
@symbol("rt_free") export fn free(p: *void, n: u64) void;
@symbol("rt_abort") fn abort(msg: str) void;
@@ -749,6 +727,29 @@ export fn exists(path: str) bool = {
return r >= 0i64;
};
// rt — runtime primitives exposed to ww programs.
// Mirrors Hare's rt:: module placement (ref/hare/rt/).
package rt;
// alloc — mmap-backed page allocator. Untyped: `alloc(n)` returns a
// `*void`; callers cast to the target type. Diverges from Hare: Hare
// exposes `alloc` / `free` as typed language builtins that the
// compiler lowers to rt::malloc/rt::free; ww has no such builtins,
// so the rt-symbol surface is exposed directly. Stdlib callers that
// need a typed allocation pattern wrap this with a cast plus a stored
// capacity (see [[strings.dup]], [[memio.dynamic]]).
//
// OOM: rt_alloc is a bare mmap(MAP_ANON|MAP_PRIVATE) wrapper with no
// error path. The raw Linux mmap syscall returns a negative errno cast
// to `*void` on failure (e.g. `(void*)-12` for ENOMEM); the
// `MAP_FAILED` (`(void*)-1`) value is a libc-wrapper convention that
// rt_alloc doesn't apply. Neither `== nil` nor `== (void*)-1` catches
// it; any deref of such a return faults. Today the stdlib does not
// check; OOM faults on first dereference. A typed fallible variant is
// a future task (task #39). ref/hare/rt/malloc.ha:27.
@symbol("rt_alloc") export fn alloc(n: u64) *void;
// selfhost/cmd/wcc/mem.ww — port of cmd/wcc/mem.c.
//
// Bump arena allocator. Backed by the runtime page allocator
@@ -762,6 +763,7 @@ export fn exists(path: str) bool = {
package wcc;
import os;
import rt;
def ALIGN: u64 = 16u64;
def INIT_CHUNK: u64 = 65536u64;
@@ -781,8 +783,8 @@ fn roundup(n: u64, a: u64) u64 = {
};
export fn newarena() *arena = {
let a: *arena = os.alloc(ARENA_SZ): *arena;
a.buf = os.alloc(INIT_CHUNK): *u8;
let a: *arena = rt.alloc(ARENA_SZ): *arena;
a.buf = rt.alloc(INIT_CHUNK): *u8;
a.off = 0u64;
a.cap = INIT_CHUNK;
a.next = nil;
@@ -799,14 +801,14 @@ fn grow(a: *arena, need: u64) bool = {
if (want > MAX_CHUNK) { want = MAX_CHUNK; };
if (want < need) { return false; }; // single allocation too big
let old: *arena = os.alloc(ARENA_SZ): *arena;
let old: *arena = rt.alloc(ARENA_SZ): *arena;
old.buf = a.buf;
old.off = a.off;
old.cap = a.cap;
old.next = a.next;
old.total = 0u64;
a.buf = os.alloc(want): *u8;
a.buf = rt.alloc(want): *u8;
a.off = 0u64;
a.cap = want;
a.next = old;
@@ -874,6 +876,7 @@ export fn freearena(a: *arena) void = {
package main;
import os;
import rt;
import mem;
// All path/string scratch buffers go on the runtime page allocator.
@@ -998,7 +1001,7 @@ fn selfdirinto(dst: *u8, dstsz: u64, argv0: *u8) void = {
// Build "$dir/$name" (NUL-terminated) into a fresh page-sized buffer.
fn joinpath(dir: *u8, name: *u8) *u8 = {
let buf: *u8 = os.alloc(PATH_MAX): *u8;
let buf: *u8 = rt.alloc(PATH_MAX): *u8;
let off: u64 = cstrinto(buf, 0u64, dir);
off = byteinto(buf, off, 47u8);
off = cstrinto(buf, off, name);
@@ -1008,7 +1011,7 @@ fn joinpath(dir: *u8, name: *u8) *u8 = {
// Same, but the second component is a ww `str` literal.
fn joinpathlit(dir: *u8, name: str) *u8 = {
let buf: *u8 = os.alloc(PATH_MAX): *u8;
let buf: *u8 = rt.alloc(PATH_MAX): *u8;
let off: u64 = cstrinto(buf, 0u64, dir);
off = byteinto(buf, off, 47u8);
off = strinto(buf, off, name);
@@ -1259,7 +1262,7 @@ fn enumeratedir(a: *arena, dirpath: *u8) (**u8, i32) = {
let names: **u8 = amalloc(a, (maxnames: u64) * 8u64): **u8;
let nlens: *u64 = amalloc(a, (maxnames: u64) * 8u64): *u64;
let n: i32 = 0;
let buf: *u8 = os.alloc(8192u64): *u8;
let buf: *u8 = rt.alloc(8192u64): *u8;
let r: i64 = os.getdents64(fd, buf, 8192u64);
for (r > 0i64) {
let off: u64 = 0u64;
@@ -1321,7 +1324,7 @@ fn slurp(pathcs: *u8) (*u8, u64) = {
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
};
let nu: u64 = n: u64;
let buf: *u8 = os.alloc(nu + 1u64): *u8;
let buf: *u8 = rt.alloc(nu + 1u64): *u8;
let rr: (i64 | os.oserror) = os.readall(fd, buf, nu);
os.close(fd);
let got: i64 = 0i64;
@@ -1428,7 +1431,7 @@ fn expand(c: *expctx, pathcs: *u8) void = {
fn peekpackage(a: *arena, pathcs: *u8) *u8 = {
let fd: i32 = os.open(pathstr(pathcs), os.flag.RDONLY, 0i32);
if (fd < 0) { return nil; };
let buf: *u8 = os.alloc(2048u64): *u8;
let buf: *u8 = rt.alloc(2048u64): *u8;
let n: i64 = os.read(fd, buf, 2048u64);
os.close(fd);
if (n <= 0i64) { return nil; };
@@ -1575,7 +1578,7 @@ fn makestem(stem: *u8, src: *u8) void = {
// Append a literal suffix to `stem` (which already lives in a buffer).
fn appendlit(stem: *u8, suffix: str) *u8 = {
let buf: *u8 = os.alloc(PATH_MAX): *u8;
let buf: *u8 = rt.alloc(PATH_MAX): *u8;
let off: u64 = cstrinto(buf, 0u64, stem);
off = strinto(buf, off, suffix);
cstrseal(buf, off);
@@ -1613,7 +1616,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
let l6: *u8 = joinpathlit(selfdir, "w6l_ww");
// Default lib search path: <selfdir>/../../lib
let dotdotlib: *u8 = os.alloc(PATH_MAX): *u8;
let dotdotlib: *u8 = rt.alloc(PATH_MAX): *u8;
{
let off: u64 = cstrinto(dotdotlib, 0u64, selfdir);
off = strinto(dotdotlib, off, "/../../lib");
@@ -1626,7 +1629,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
// convention assumes you're running from the module dir; our
// wrappers don't cd, so dirname(src) stands in as the closest
// analog. Source-dir wins ties over the system path (cc -I.).
let srcd: *u8 = os.alloc(PATH_MAX): *u8;
let srcd: *u8 = rt.alloc(PATH_MAX): *u8;
if (entryisdir != 0) {
let slen: u64 = cstrlen(src);
let k: u64 = 0u64;
@@ -1660,7 +1663,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
};
// Compose searchpath: srcd + ':' + incs + ':' + dotdotlib.
let searchpath: *u8 = os.alloc(PATH_MAX * 3u64): *u8;
let searchpath: *u8 = rt.alloc(PATH_MAX * 3u64): *u8;
{
let off: u64 = cstrinto(searchpath, 0u64, srcd);
off = byteinto(searchpath, off, 58u8); // ':'
@@ -1674,7 +1677,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
// Stem for .s/.o/.combined.ww side files. Dir entry: <dir>/<base>;
// file entry: src stripped of .ww.
let stem: *u8 = os.alloc(PATH_MAX): *u8;
let stem: *u8 = rt.alloc(PATH_MAX): *u8;
if (entryisdir != 0) {
let dlen: u64 = cstrlen(srcd);
let bo: u64 = basenameoff(srcd, dlen);
@@ -1691,7 +1694,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
let combined: *u8 = appendlit(stem, ".combined.ww");
// libwwrt.a path: <selfdir>/../lib/libwwrt.a
let libwwrt: *u8 = os.alloc(PATH_MAX): *u8;
let libwwrt: *u8 = rt.alloc(PATH_MAX): *u8;
{
let off: u64 = cstrinto(libwwrt, 0u64, selfdir);
off = strinto(libwwrt, off, "/../lib/libwwrt.a");
@@ -1718,7 +1721,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
// Step 2: w6c -o <stem>.s <stem>.combined.ww
{
let argv: **u8 = os.alloc(40u64): **u8;
let argv: **u8 = rt.alloc(40u64): **u8;
argv[0] = "w6c\0".ptr;
argv[1] = "-o\0".ptr;
argv[2] = asmf;
@@ -1732,7 +1735,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
// Step 3: w6a -o <stem>.o <stem>.s
{
let argv: **u8 = os.alloc(40u64): **u8;
let argv: **u8 = rt.alloc(40u64): **u8;
argv[0] = "w6a\0".ptr;
argv[1] = "-o\0".ptr;
argv[2] = objf;
@@ -1761,7 +1764,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
// + 2 * nlibs (-l, name)
// + 1 nil terminator.
let total: i32 = 5 + 2 * nldirs + 2 * nllibs + 1;
let argv: **u8 = os.alloc((total: u64) * 8u64): **u8;
let argv: **u8 = rt.alloc((total: u64) * 8u64): **u8;
argv[0] = "w6l\0".ptr;
argv[1] = "-o\0".ptr;
argv[2] = out;
@@ -1933,7 +1936,7 @@ fn defaultoutpath(src: *u8) *u8 = {
if (src[i] == 47u8) { start = i + 1u64; }; // '/'
i += 1u64;
};
let out: *u8 = os.alloc(PATH_MAX): *u8;
let out: *u8 = rt.alloc(PATH_MAX): *u8;
let off: u64 = 0u64;
let j: u64 = start;
for (j < n) {
@@ -1958,14 +1961,14 @@ fn defaultoutpath(src: *u8) *u8 = {
fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
let a: *arena = newarena();
let src: *u8 = nil;
let incs: *u8 = os.alloc(PATH_MAX * 2u64): *u8;
let incs: *u8 = rt.alloc(PATH_MAX * 2u64): *u8;
let incoff: u64 = 0u64;
cstrseal(incs, 0u64);
let maxlflags: i32 = 32;
let libdirs: **u8 = os.alloc((maxlflags: u64) * 8u64): **u8;
let libdirs: **u8 = rt.alloc((maxlflags: u64) * 8u64): **u8;
let nlibdirs: i32 = 0;
let libs: **u8 = os.alloc((maxlflags: u64) * 8u64): **u8;
let libs: **u8 = rt.alloc((maxlflags: u64) * 8u64): **u8;
let nlibs: i32 = 0;
let i: i32 = start;
@@ -2055,7 +2058,7 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
rlen -= 1u64;
};
let bo: u64 = basenameoff(resolved, rlen);
out = os.alloc(PATH_MAX): *u8;
out = rt.alloc(PATH_MAX): *u8;
let i: u64 = bo;
let off: u64 = 0u64;
for (i < rlen) { out[off] = resolved[i]; off += 1u64; i += 1u64; };
@@ -2105,14 +2108,14 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
let a: *arena = newarena();
let src: *u8 = nil;
let passstart: i32 = -1; // first argv idx to pass through to program
let incs: *u8 = os.alloc(PATH_MAX * 2u64): *u8;
let incs: *u8 = rt.alloc(PATH_MAX * 2u64): *u8;
let incoff: u64 = 0u64;
cstrseal(incs, 0u64);
let maxlflags: i32 = 32;
let libdirs: **u8 = os.alloc((maxlflags: u64) * 8u64): **u8;
let libdirs: **u8 = rt.alloc((maxlflags: u64) * 8u64): **u8;
let nlibdirs: i32 = 0;
let libs: **u8 = os.alloc((maxlflags: u64) * 8u64): **u8;
let libs: **u8 = rt.alloc((maxlflags: u64) * 8u64): **u8;
let nlibs: i32 = 0;
let i: i32 = start;
@@ -2202,7 +2205,7 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
return 1;
};
let tmp: *u8 = os.alloc(PATH_MAX): *u8;
let tmp: *u8 = rt.alloc(PATH_MAX): *u8;
makeruntmp(tmp);
let lf: lflags;
lf.libdirs = libdirs;
@@ -2218,7 +2221,7 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
let nextra: i32 = 0;
if (passstart >= 0) { nextra = argc - passstart; };
let total: i32 = nextra + 2;
let execargv: **u8 = os.alloc((total: u64) * 8u64): **u8;
let execargv: **u8 = rt.alloc((total: u64) * 8u64): **u8;
execargv[0] = tmp;
let k: i32 = 0;
for (k < nextra) {
@@ -2239,13 +2242,13 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
// report ok/FAIL per file, return 0 iff all pass.
fn runsingletest(selfdir: *u8, src: *u8) i32 = {
let tmp: *u8 = os.alloc(PATH_MAX): *u8;
let tmp: *u8 = rt.alloc(PATH_MAX): *u8;
makeruntmp(tmp);
if (buildone(selfdir, src, 0, tmp, "\0".ptr, nil) != 0) {
os.remove(pathstr(tmp));
return 1;
};
let execargv: **u8 = os.alloc(16u64): **u8;
let execargv: **u8 = rt.alloc(16u64): **u8;
execargv[0] = tmp;
execargv[1] = nil;
let rc: i32 = procrun(tmp, execargv);
@@ -2262,7 +2265,7 @@ fn rundirtests(selfdir: *u8, dir: *u8) i32 = {
let pass: i32 = 0;
let fail: i32 = 0;
let buf: *u8 = os.alloc(8192u64): *u8;
let buf: *u8 = rt.alloc(8192u64): *u8;
let dirlen: u64 = cstrlen(dir);
let n: i64 = os.getdents64(fd, buf, 8192u64);
@@ -2278,7 +2281,7 @@ fn rundirtests(selfdir: *u8, dir: *u8) i32 = {
if (cstrendswithlit(name, "_test.ww")) {
let nlen: u64 = cstrlen(name);
// path = <dir>/<name>
let path: *u8 = os.alloc(PATH_MAX): *u8;
let path: *u8 = rt.alloc(PATH_MAX): *u8;
let poff: u64 = cstrinto(path, 0u64, dir);
path[poff] = 47u8; poff += 1u64;
let i: u64 = 0u64;
@@ -2286,10 +2289,10 @@ fn rundirtests(selfdir: *u8, dir: *u8) i32 = {
poff += nlen;
cstrseal(path, poff);
// incs = <dir> so test files can `use ` siblings
let tincs: *u8 = os.alloc(PATH_MAX): *u8;
let tincs: *u8 = rt.alloc(PATH_MAX): *u8;
let ic: u64 = cstrinto(tincs, 0u64, dir);
cstrseal(tincs, ic);
let tmp: *u8 = os.alloc(PATH_MAX): *u8;
let tmp: *u8 = rt.alloc(PATH_MAX): *u8;
makeruntmp(tmp);
let bres: i32 = buildone(selfdir, path, 0, tmp, tincs, nil);
if (bres != 0) {
@@ -2298,7 +2301,7 @@ fn rundirtests(selfdir: *u8, dir: *u8) i32 = {
os.write(2, name, nlen);
os.write(2, " (build)\n".ptr, 9u64);
} else {
let execargv: **u8 = os.alloc(16u64): **u8;
let execargv: **u8 = rt.alloc(16u64): **u8;
execargv[0] = tmp;
execargv[1] = nil;
let rc: i32 = procrun(tmp, execargv);
@@ -2355,7 +2358,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
};
// selfdir = dirname(argv[0])
let selfdir: *u8 = os.alloc(PATH_MAX): *u8;
let selfdir: *u8 = rt.alloc(PATH_MAX): *u8;
selfdirinto(selfdir, PATH_MAX, argv[0]);
if (argc < 2) {

View File

@@ -14,6 +14,7 @@
package main;
import os;
import rt;
import mem;
// All path/string scratch buffers go on the runtime page allocator.
@@ -138,7 +139,7 @@ fn selfdirinto(dst: *u8, dstsz: u64, argv0: *u8) void = {
// Build "$dir/$name" (NUL-terminated) into a fresh page-sized buffer.
fn joinpath(dir: *u8, name: *u8) *u8 = {
let buf: *u8 = os.alloc(PATH_MAX): *u8;
let buf: *u8 = rt.alloc(PATH_MAX): *u8;
let off: u64 = cstrinto(buf, 0u64, dir);
off = byteinto(buf, off, 47u8);
off = cstrinto(buf, off, name);
@@ -148,7 +149,7 @@ fn joinpath(dir: *u8, name: *u8) *u8 = {
// Same, but the second component is a ww `str` literal.
fn joinpathlit(dir: *u8, name: str) *u8 = {
let buf: *u8 = os.alloc(PATH_MAX): *u8;
let buf: *u8 = rt.alloc(PATH_MAX): *u8;
let off: u64 = cstrinto(buf, 0u64, dir);
off = byteinto(buf, off, 47u8);
off = strinto(buf, off, name);
@@ -399,7 +400,7 @@ fn enumeratedir(a: *arena, dirpath: *u8) (**u8, i32) = {
let names: **u8 = amalloc(a, (maxnames: u64) * 8u64): **u8;
let nlens: *u64 = amalloc(a, (maxnames: u64) * 8u64): *u64;
let n: i32 = 0;
let buf: *u8 = os.alloc(8192u64): *u8;
let buf: *u8 = rt.alloc(8192u64): *u8;
let r: i64 = os.getdents64(fd, buf, 8192u64);
for (r > 0i64) {
let off: u64 = 0u64;
@@ -461,7 +462,7 @@ fn slurp(pathcs: *u8) (*u8, u64) = {
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
};
let nu: u64 = n: u64;
let buf: *u8 = os.alloc(nu + 1u64): *u8;
let buf: *u8 = rt.alloc(nu + 1u64): *u8;
let rr: (i64 | os.oserror) = os.readall(fd, buf, nu);
os.close(fd);
let got: i64 = 0i64;
@@ -568,7 +569,7 @@ fn expand(c: *expctx, pathcs: *u8) void = {
fn peekpackage(a: *arena, pathcs: *u8) *u8 = {
let fd: i32 = os.open(pathstr(pathcs), os.flag.RDONLY, 0i32);
if (fd < 0) { return nil; };
let buf: *u8 = os.alloc(2048u64): *u8;
let buf: *u8 = rt.alloc(2048u64): *u8;
let n: i64 = os.read(fd, buf, 2048u64);
os.close(fd);
if (n <= 0i64) { return nil; };
@@ -715,7 +716,7 @@ fn makestem(stem: *u8, src: *u8) void = {
// Append a literal suffix to `stem` (which already lives in a buffer).
fn appendlit(stem: *u8, suffix: str) *u8 = {
let buf: *u8 = os.alloc(PATH_MAX): *u8;
let buf: *u8 = rt.alloc(PATH_MAX): *u8;
let off: u64 = cstrinto(buf, 0u64, stem);
off = strinto(buf, off, suffix);
cstrseal(buf, off);
@@ -753,7 +754,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
let l6: *u8 = joinpathlit(selfdir, "w6l_ww");
// Default lib search path: <selfdir>/../../lib
let dotdotlib: *u8 = os.alloc(PATH_MAX): *u8;
let dotdotlib: *u8 = rt.alloc(PATH_MAX): *u8;
{
let off: u64 = cstrinto(dotdotlib, 0u64, selfdir);
off = strinto(dotdotlib, off, "/../../lib");
@@ -766,7 +767,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
// convention assumes you're running from the module dir; our
// wrappers don't cd, so dirname(src) stands in as the closest
// analog. Source-dir wins ties over the system path (cc -I.).
let srcd: *u8 = os.alloc(PATH_MAX): *u8;
let srcd: *u8 = rt.alloc(PATH_MAX): *u8;
if (entryisdir != 0) {
let slen: u64 = cstrlen(src);
let k: u64 = 0u64;
@@ -800,7 +801,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
};
// Compose searchpath: srcd + ':' + incs + ':' + dotdotlib.
let searchpath: *u8 = os.alloc(PATH_MAX * 3u64): *u8;
let searchpath: *u8 = rt.alloc(PATH_MAX * 3u64): *u8;
{
let off: u64 = cstrinto(searchpath, 0u64, srcd);
off = byteinto(searchpath, off, 58u8); // ':'
@@ -814,7 +815,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
// Stem for .s/.o/.combined.ww side files. Dir entry: <dir>/<base>;
// file entry: src stripped of .ww.
let stem: *u8 = os.alloc(PATH_MAX): *u8;
let stem: *u8 = rt.alloc(PATH_MAX): *u8;
if (entryisdir != 0) {
let dlen: u64 = cstrlen(srcd);
let bo: u64 = basenameoff(srcd, dlen);
@@ -831,7 +832,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
let combined: *u8 = appendlit(stem, ".combined.ww");
// libwwrt.a path: <selfdir>/../lib/libwwrt.a
let libwwrt: *u8 = os.alloc(PATH_MAX): *u8;
let libwwrt: *u8 = rt.alloc(PATH_MAX): *u8;
{
let off: u64 = cstrinto(libwwrt, 0u64, selfdir);
off = strinto(libwwrt, off, "/../lib/libwwrt.a");
@@ -858,7 +859,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
// Step 2: w6c -o <stem>.s <stem>.combined.ww
{
let argv: **u8 = os.alloc(40u64): **u8;
let argv: **u8 = rt.alloc(40u64): **u8;
argv[0] = "w6c\0".ptr;
argv[1] = "-o\0".ptr;
argv[2] = asmf;
@@ -872,7 +873,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
// Step 3: w6a -o <stem>.o <stem>.s
{
let argv: **u8 = os.alloc(40u64): **u8;
let argv: **u8 = rt.alloc(40u64): **u8;
argv[0] = "w6a\0".ptr;
argv[1] = "-o\0".ptr;
argv[2] = objf;
@@ -901,7 +902,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
// + 2 * nlibs (-l, name)
// + 1 nil terminator.
let total: i32 = 5 + 2 * nldirs + 2 * nllibs + 1;
let argv: **u8 = os.alloc((total: u64) * 8u64): **u8;
let argv: **u8 = rt.alloc((total: u64) * 8u64): **u8;
argv[0] = "w6l\0".ptr;
argv[1] = "-o\0".ptr;
argv[2] = out;
@@ -1073,7 +1074,7 @@ fn defaultoutpath(src: *u8) *u8 = {
if (src[i] == 47u8) { start = i + 1u64; }; // '/'
i += 1u64;
};
let out: *u8 = os.alloc(PATH_MAX): *u8;
let out: *u8 = rt.alloc(PATH_MAX): *u8;
let off: u64 = 0u64;
let j: u64 = start;
for (j < n) {
@@ -1098,14 +1099,14 @@ fn defaultoutpath(src: *u8) *u8 = {
fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
let a: *arena = newarena();
let src: *u8 = nil;
let incs: *u8 = os.alloc(PATH_MAX * 2u64): *u8;
let incs: *u8 = rt.alloc(PATH_MAX * 2u64): *u8;
let incoff: u64 = 0u64;
cstrseal(incs, 0u64);
let maxlflags: i32 = 32;
let libdirs: **u8 = os.alloc((maxlflags: u64) * 8u64): **u8;
let libdirs: **u8 = rt.alloc((maxlflags: u64) * 8u64): **u8;
let nlibdirs: i32 = 0;
let libs: **u8 = os.alloc((maxlflags: u64) * 8u64): **u8;
let libs: **u8 = rt.alloc((maxlflags: u64) * 8u64): **u8;
let nlibs: i32 = 0;
let i: i32 = start;
@@ -1195,7 +1196,7 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
rlen -= 1u64;
};
let bo: u64 = basenameoff(resolved, rlen);
out = os.alloc(PATH_MAX): *u8;
out = rt.alloc(PATH_MAX): *u8;
let i: u64 = bo;
let off: u64 = 0u64;
for (i < rlen) { out[off] = resolved[i]; off += 1u64; i += 1u64; };
@@ -1245,14 +1246,14 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
let a: *arena = newarena();
let src: *u8 = nil;
let passstart: i32 = -1; // first argv idx to pass through to program
let incs: *u8 = os.alloc(PATH_MAX * 2u64): *u8;
let incs: *u8 = rt.alloc(PATH_MAX * 2u64): *u8;
let incoff: u64 = 0u64;
cstrseal(incs, 0u64);
let maxlflags: i32 = 32;
let libdirs: **u8 = os.alloc((maxlflags: u64) * 8u64): **u8;
let libdirs: **u8 = rt.alloc((maxlflags: u64) * 8u64): **u8;
let nlibdirs: i32 = 0;
let libs: **u8 = os.alloc((maxlflags: u64) * 8u64): **u8;
let libs: **u8 = rt.alloc((maxlflags: u64) * 8u64): **u8;
let nlibs: i32 = 0;
let i: i32 = start;
@@ -1342,7 +1343,7 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
return 1;
};
let tmp: *u8 = os.alloc(PATH_MAX): *u8;
let tmp: *u8 = rt.alloc(PATH_MAX): *u8;
makeruntmp(tmp);
let lf: lflags;
lf.libdirs = libdirs;
@@ -1358,7 +1359,7 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
let nextra: i32 = 0;
if (passstart >= 0) { nextra = argc - passstart; };
let total: i32 = nextra + 2;
let execargv: **u8 = os.alloc((total: u64) * 8u64): **u8;
let execargv: **u8 = rt.alloc((total: u64) * 8u64): **u8;
execargv[0] = tmp;
let k: i32 = 0;
for (k < nextra) {
@@ -1379,13 +1380,13 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
// report ok/FAIL per file, return 0 iff all pass.
fn runsingletest(selfdir: *u8, src: *u8) i32 = {
let tmp: *u8 = os.alloc(PATH_MAX): *u8;
let tmp: *u8 = rt.alloc(PATH_MAX): *u8;
makeruntmp(tmp);
if (buildone(selfdir, src, 0, tmp, "\0".ptr, nil) != 0) {
os.remove(pathstr(tmp));
return 1;
};
let execargv: **u8 = os.alloc(16u64): **u8;
let execargv: **u8 = rt.alloc(16u64): **u8;
execargv[0] = tmp;
execargv[1] = nil;
let rc: i32 = procrun(tmp, execargv);
@@ -1402,7 +1403,7 @@ fn rundirtests(selfdir: *u8, dir: *u8) i32 = {
let pass: i32 = 0;
let fail: i32 = 0;
let buf: *u8 = os.alloc(8192u64): *u8;
let buf: *u8 = rt.alloc(8192u64): *u8;
let dirlen: u64 = cstrlen(dir);
let n: i64 = os.getdents64(fd, buf, 8192u64);
@@ -1418,7 +1419,7 @@ fn rundirtests(selfdir: *u8, dir: *u8) i32 = {
if (cstrendswithlit(name, "_test.ww")) {
let nlen: u64 = cstrlen(name);
// path = <dir>/<name>
let path: *u8 = os.alloc(PATH_MAX): *u8;
let path: *u8 = rt.alloc(PATH_MAX): *u8;
let poff: u64 = cstrinto(path, 0u64, dir);
path[poff] = 47u8; poff += 1u64;
let i: u64 = 0u64;
@@ -1426,10 +1427,10 @@ fn rundirtests(selfdir: *u8, dir: *u8) i32 = {
poff += nlen;
cstrseal(path, poff);
// incs = <dir> so test files can `use ` siblings
let tincs: *u8 = os.alloc(PATH_MAX): *u8;
let tincs: *u8 = rt.alloc(PATH_MAX): *u8;
let ic: u64 = cstrinto(tincs, 0u64, dir);
cstrseal(tincs, ic);
let tmp: *u8 = os.alloc(PATH_MAX): *u8;
let tmp: *u8 = rt.alloc(PATH_MAX): *u8;
makeruntmp(tmp);
let bres: i32 = buildone(selfdir, path, 0, tmp, tincs, nil);
if (bres != 0) {
@@ -1438,7 +1439,7 @@ fn rundirtests(selfdir: *u8, dir: *u8) i32 = {
os.write(2, name, nlen);
os.write(2, " (build)\n".ptr, 9u64);
} else {
let execargv: **u8 = os.alloc(16u64): **u8;
let execargv: **u8 = rt.alloc(16u64): **u8;
execargv[0] = tmp;
execargv[1] = nil;
let rc: i32 = procrun(tmp, execargv);
@@ -1495,7 +1496,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
};
// selfdir = dirname(argv[0])
let selfdir: *u8 = os.alloc(PATH_MAX): *u8;
let selfdir: *u8 = rt.alloc(PATH_MAX): *u8;
selfdirinto(selfdir, PATH_MAX, argv[0]);
if (argc < 2) {