feat(compiler): #75 resolve the auto-spliced engine runtime from LUDIC_HOME
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 23s
ci / build-and-test (push) Successful in 2m25s
commit-lint / conventional-commits (push) Successful in 6s
docs / build-and-deploy (push) Successful in 28s

The compiler auto-splices runtime/native/* for any ECS game, but resolved it
relative to the build CWD, then fell back to the package module root
($LUDIC_MODULES) — forcing every external project to copy/symlink the engine
runtime into ludic_modules/. The runtime is part of the toolchain, not the
project: do_import now resolves a runtime/... import that isn't found locally
from $LUDIC_HOME (default: the compiler binary's dir — where cocoa.ll/audio.ll
already come from), before the module root. So ludic_modules/ holds only
third-party packages.

In-repo builds are byte-identical (the runtime resolves locally there, so the
$LUDIC_HOME fallback never fires; fixpoint holds). Verified by a hermetic test
that builds an ECS game from an external CWD with no runtime/ or ludic_modules/
under it, resolving the runtime from LUDIC_HOME. Full suite 113/0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-02 07:49:10 +03:00
parent ad3be0c53c
commit ab4546e365
5 changed files with 17240 additions and 17005 deletions

View file

@ -662,9 +662,35 @@ function parse_test() -> Node {
# materialised by `x get` at ludic_modules/git.workshopsoft.io/user/pkg/foo.ludic.
# The fallback only fires when the local path does not exist, so every existing
# import resolves exactly as before (the emitted IR is byte-identical).
# true when `rel` is an engine-runtime splice path ("runtime/..."), as opposed to
# a user or package import. Those ship with the toolchain, not the project (#75).
function is_runtime_path(rel: pointer) -> bool {
if rel[0] != 114 { return false } # r
if rel[1] != 117 { return false } # u
if rel[2] != 110 { return false } # n
if rel[3] != 116 { return false } # t
if rel[4] != 105 { return false } # i
if rel[5] != 109 { return false } # m
if rel[6] != 101 { return false } # e
if rel[7] != 47 { return false } # /
return true
}
function do_import(rel: pointer) -> void {
var full = path_join(cur_dir, rel)
var src = read_file(full)
# #75 — the engine runtime (runtime/native/*) ships with the toolchain, not the
# project. When an auto-spliced runtime import is not found relative to the build
# (an external game whose CWD is not the toolchain repo), resolve it from the
# install root $LUDIC_HOME (default: the compiler binary's directory) — the same
# place main.ludic finds cocoa.ll / audio.ll. This is tried before the package
# module root, so $LUDIC_MODULES / ludic_modules holds only third-party packages.
if (src == null) and (rel[0] != 47) and is_runtime_path(rel) {
let home = ensure_slash(getenv_or("LUDIC_HOME", dir_of(arg(0))))
let hc = home + rel
let hs = read_file(hc)
if (hs != null) { full = hc; src = hs }
}
if (src == null) and (rel[0] != 47) {
let cand = ensure_slash(getenv_or("LUDIC_MODULES", "ludic_modules")) + rel
let s2 = read_file(cand)

File diff suppressed because it is too large Load diff