From 5a2e4ba28dfecda569015deb8a96d6fe5a593f7d Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Wed, 12 Aug 2026 15:18:46 +0900 Subject: [PATCH] cmd: honor package library roots in both stages --- cmd/ww/main.c | 31 +++++++----- selfhost/cmd/ww/main.ww | 104 +++++++++++++++++++++++++++++----------- 2 files changed, 94 insertions(+), 41 deletions(-) diff --git a/cmd/ww/main.c b/cmd/ww/main.c index ace14165..417d1b32 100644 --- a/cmd/ww/main.c +++ b/cmd/ww/main.c @@ -33,11 +33,18 @@ static const char *usage = static char *self_dir; +static const char * +envpath(const char *name) +{ + const char *p = getenv(name); + return p && p[0] ? p : NULL; +} + static const char * toolpath(const char *envvar, const char *name) { - const char *p = getenv(envvar); - if (p && p[0]) return p; + const char *p = envpath(envvar); + if (p) return p; static char buf[1024]; snprintf(buf, sizeof buf, "%s/%s", self_dir, name); return strdup(buf); @@ -1681,15 +1688,15 @@ build_one_sep_impl(const char *src, int entry_is_dir, const char *c6 = toolpath("WW_W6C", "w6c"); const char *a6 = toolpath("WW_W6A", "w6a"); const char *l6 = toolpath("WW_W6L", "w6l"); - const char *libdir = getenv("WW_LIB"); - if (libdir == NULL || libdir[0] == 0) { + const char *libdir = envpath("WW_LIB"); + if (libdir == NULL) { static char libbuf[1024]; snprintf(libbuf, sizeof libbuf, "%s/../lib", self_dir); libdir = libbuf; } - const char *srcdir = getenv("WW_SRCLIB"); + const char *srcdir = envpath("WW_SRCLIB"); static char srcbuf[1024]; - if (srcdir == NULL || srcdir[0] == 0) { + if (srcdir == NULL) { snprintf(srcbuf, sizeof srcbuf, "%s/../../lib", self_dir); if (access(srcbuf, 0) == 0) srcdir = srcbuf; else if (access("lib", 0) == 0) srcdir = "lib"; @@ -2267,17 +2274,17 @@ do_version(void) return 0; } -/* Compose the standard module search path: cwd : : $WW_LIB - * source dir. The `extra` string is colon-separated -I dirs from argv. */ +/* Compose the standard module search path: cwd : : selected + * source library. The `extra` string is colon-separated -I dirs from argv. */ static const char * search_path(const char *extra, char *buf, size_t bufsz) { - const char *libdir = getenv("WW_SRCLIB"); + const char *libdir = envpath("WW_SRCLIB"); static char libbuf[1024]; - if (libdir == NULL || libdir[0] == 0) { - libdir = getenv("WW_LIB"); + if (libdir == NULL) { + libdir = envpath("WW_LIB"); } - if (libdir == NULL || libdir[0] == 0) { + if (libdir == NULL) { snprintf(libbuf, sizeof libbuf, "%s/../../lib", self_dir); if (access(libbuf, 0) == 0) libdir = libbuf; else if (access("lib", 0) == 0) libdir = "lib"; diff --git a/selfhost/cmd/ww/main.ww b/selfhost/cmd/ww/main.ww index 0a9238e7..bc7868ee 100644 --- a/selfhost/cmd/ww/main.ww +++ b/selfhost/cmd/ww/main.ww @@ -9,7 +9,7 @@ // // Tool paths default to siblings of $0 so a fresh build runs out of // out/bin/. WW_W6C / WW_W6A / WW_W6L select exact executable paths. -// Source-library and runtime-library overrides are not yet supported. +// WW_SRCLIB selects package sources and WW_LIB selects runtime artifacts. package main; @@ -162,13 +162,19 @@ fn owncstr(s: str) *u8 = { return b.ptr; }; -fn toolpath(selfdir: *u8, envvar: str, name: str) *u8 = { - match (os.getenv(envvar)) { +fn envpath(name: str) *u8 = { + match (os.getenv(name)) { case let p: str => { if (p.len != 0) { return owncstr(p); }; }; case void => void; }; + return nil; +}; + +fn toolpath(selfdir: *u8, envvar: str, name: str) *u8 = { + let p: *u8 = envpath(envvar); + if (p != nil) { return p; }; return joinpathlit(selfdir, name); }; @@ -285,6 +291,11 @@ fn importpathform(name: *u8, namelen: u64) *u8 = { // `foo/foo.ha` fallback; a module IS the directory). fn locatein(dir: *u8, dirlen: u64, pathform: *u8, pflen: u64, isdir: *i32, wantdir: i32) *u8 = { + let tail: u64 = 1u64; // NUL for the directory form + if (wantdir == 0i32) { tail = 4u64; }; // ".ww" + NUL + if (dirlen + 1u64 + pflen + tail > os.PATH_MAX: u64) { + return nil; + }; let buf: []u8 = alloc([], (os.PATH_MAX: u64))!; let off: u64 = 0u64; let i: u64 = 0u64; @@ -2031,13 +2042,18 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, let c6: *u8 = toolpath(selfdir, "WW_W6C", "w6c_ww"); let a6: *u8 = toolpath(selfdir, "WW_W6A", "w6a_ww"); let l6: *u8 = toolpath(selfdir, "WW_W6L", "w6l_ww"); - - let dotdotlib: []u8 = alloc([], (os.PATH_MAX: u64))!; - dotdotlib.len = os.PATH_MAX; - { - let off: u64 = cstrinto(dotdotlib.ptr, 0u64, selfdir); - off = strinto(dotdotlib.ptr, off, "/../../lib"); - cstrseal(dotdotlib.ptr, off); + let libdir: *u8 = envpath("WW_LIB"); + if (libdir == nil) { libdir = joinpathlit(selfdir, "../lib"); }; + let toolsrcdir: *u8 = envpath("WW_SRCLIB"); + if (toolsrcdir == nil) { + let candidate: *u8 = joinpathlit(selfdir, "../../lib"); + if (os.access(pathstr(candidate), 0i32) == 0) { + toolsrcdir = candidate; + } else { if (os.access("lib", 0i32) == 0) { + toolsrcdir = "lib\0".ptr; + } else { + toolsrcdir = libdir; + }; }; }; let srcd: []u8 = alloc([], (os.PATH_MAX: u64))!; @@ -2144,12 +2160,21 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, if (staleall && invalidateworkdirunits(scratch) != 0) { return 1; }; }; - let libwwrt: []u8 = alloc([], (os.PATH_MAX: u64))!; - libwwrt.len = os.PATH_MAX; - { - let off: u64 = cstrinto(libwwrt.ptr, 0u64, selfdir); - off = strinto(libwwrt.ptr, off, "/../lib/libwwrt.a"); - cstrseal(libwwrt.ptr, off); + let rtpaths: []*u8 = alloc([], 2u64)!; + rtpaths.len = 2; + let nrt: i32 = 1; + let havearchive: bool = false; + if (cstrlen(libdir) + 1u64 + "libwwrt.a".len: u64 + 1u64 + <= os.PATH_MAX: u64) { + rtpaths[0] = joinpathlit(libdir, "libwwrt.a"); + if (os.access(pathstr(rtpaths[0]), 0i32) == 0) { + havearchive = true; + }; + }; + if (!havearchive) { + nrt = 2; + rtpaths[0] = joinpathlit(selfdir, "../obj/rt/start.o"); + rtpaths[1] = joinpathlit(selfdir, "../obj/rt/syscall.o"); }; let pkgslot: []seppkg = alloc([], SEP_MAXPKG: u64)!; @@ -2175,7 +2200,7 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, let contextroot: *u8 = entry; if (entryisdir == 0) { contextroot = srcd.ptr; }; products[producti].context = sepcontextfor(g, contextroot, - incs, dotdotlib.ptr); + incs, toolsrcdir); if (products[producti].context < 0) { return 1; }; products[producti].root = sepfindoraddvariant(g, rootpath, entry, entryisdir, products[producti].variant, @@ -2192,11 +2217,11 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, // it distinct. The linker receives the same support archive closure. if (istest != 0) { let td: i32 = 0; - let tp: *u8 = locateimport(dotdotlib.ptr, "test".ptr, + let tp: *u8 = locateimport(toolsrcdir, "test".ptr, "test".len: u64, &td); if (tp != nil) { - g.supportcontext = sepcontextfor(g, dotdotlib.ptr, nil, - dotdotlib.ptr); + g.supportcontext = sepcontextfor(g, toolsrcdir, nil, + toolsrcdir); if (g.supportcontext < 0) { return 1; }; let collision: bool = false; producti = 0; @@ -2629,8 +2654,8 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, let nlink: i32 = 0; if (septopovisit(g, root, linkorder, &nlink, linkstack, 0) < 0) { return 1; }; - // argv: 3 fixed + closure + libwwrt + joined flags + nil. - let total: i32 = 3 + nlink + 1 + nldirs + nllibs + 1; + // argv: 3 fixed + closure + runtime inputs + joined flags + nil. + let total: i32 = 3 + nlink + nrt + nldirs + nllibs + 1; let largv: []*u8 = alloc([], total: u64)!; largv.len = total; largv[0] = "w6l\0".ptr; @@ -2655,7 +2680,12 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, pos += 1; li -= 1; }; - largv[pos] = libwwrt.ptr; pos += 1; + let ri: i32 = 0; + for (ri < nrt) { + largv[pos] = rtpaths[ri]; + pos += 1; + ri += 1; + }; let k: i32 = 0; for (k < nldirs) { let n: u64 = cstrlen(ldirs[k]); @@ -2817,9 +2847,26 @@ fn arenadupcstr(src: *u8, plen: u64) *u8 = { return buf.ptr; }; -// resolvemodule search-path order: "." : : /../../lib +// resolvemodule search-path order: "." : : selected source library. fn buildsearchpath(selfdir: *u8, incs: *u8) *u8 = { - let buf: []u8 = alloc([], (os.PATH_MAX: u64) * 2u64)!; + let libdir: *u8 = envpath("WW_SRCLIB"); + if (libdir == nil) { libdir = envpath("WW_LIB"); }; + if (libdir == nil) { + let candidate: *u8 = joinpathlit(selfdir, "../../lib"); + if (os.access(pathstr(candidate), 0i32) == 0) { + libdir = candidate; + } else { if (os.access("lib", 0i32) == 0) { + libdir = "lib\0".ptr; + } else { + libdir = joinpathlit(selfdir, "../lib"); + }; }; + }; + let need: u64 = 1u64 + 1u64 + cstrlen(libdir) + 1u64; + if (incs != nil && incs[0u64] != 0u8) { + need += cstrlen(incs) + 1u64; + }; + let buf: []u8 = alloc([], need)!; + buf.len = need: i32; let off: u64 = 0u64; buf[off] = 46u8; off += 1u64; // '.' if (incs != nil) { @@ -2829,8 +2876,7 @@ fn buildsearchpath(selfdir: *u8, incs: *u8) *u8 = { }; }; buf[off] = 58u8; off += 1u64; - off = cstrinto(buf.ptr, off, selfdir); - off = strinto(buf.ptr, off, "/../../lib"); + off = cstrinto(buf.ptr, off, libdir); cstrseal(buf.ptr, off); return buf.ptr; }; @@ -3038,7 +3084,7 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = { let isdir: i32 = 0; let resolved: *u8 = resolvemodule(selfdir, src, incs.ptr, &isdir); if (resolved == nil) { - cerr("ww build: cannot find module\n"); + cerrpath("ww build: cannot find module ", src, "\n"); return 1; }; if (packageonly != 0 && isdir == 0) { @@ -3225,7 +3271,7 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = { let isdir: i32 = 0; let resolved: *u8 = resolvemodule(selfdir, src, incs.ptr, &isdir); if (resolved == nil) { - cerr("ww run: cannot find module\n"); + cerrpath("ww run: cannot find module ", src, "\n"); return 1; };