From be04ebe9548959514fb3fd7b7b734bb6041267ba Mon Sep 17 00:00:00 2001 From: Daniel Samson <12231216+daniel-samson@users.noreply.github.com> Date: Thu, 30 Jul 2026 07:49:19 +0100 Subject: [PATCH] =?UTF-8?q?build:=20delete=20module=5Fhomes=20=E2=80=94=20?= =?UTF-8?q?imports=20resolve=20through=20the=20declared=20zon?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The module-to-domain table in build-support duplicated what each domain's build.zig already states with its addModule exports. userBinary now resolves each named import by searching the packages the binary declared in its own build.zig.zon (b.available_deps), which also makes the zon the literal include path: an import can only be satisfied by a domain the binary claims, and naming a module whose domain is missing fails the build graph with the domain to declare. build-support is down to the recipe alone. All build variants green; manifest unchanged. --- build-support/build.zig | 80 +++++-------------- docs/build-packages-plan.md | 12 +-- system/drivers/pci-bus/build.zig | 2 +- system/drivers/ps2-bus/build.zig | 2 +- system/drivers/usb-hid/build.zig | 2 +- system/drivers/usb-storage/build.zig | 2 +- system/drivers/usb-xhci-bus/build.zig | 2 +- system/drivers/virtio-gpu/build.zig | 2 +- system/services/acpi/build.zig | 2 +- system/services/device-manager/build.zig | 2 +- system/services/display-demo/build.zig | 2 +- system/services/display/build.zig | 2 +- system/services/fat/build.zig | 2 +- system/services/fdt/build.zig | 2 +- system/services/init/build.zig | 2 +- system/services/input/build.zig | 2 +- test/system/services/args-echo/build.zig | 2 +- test/system/services/crash-test/build.zig | 2 +- test/system/services/device-list/build.zig | 2 +- test/system/services/fat-test/build.zig | 2 +- test/system/services/input-source/build.zig | 2 +- test/system/services/input-test/build.zig | 2 +- .../services/iommu-fault-test/build.zig | 2 +- test/system/services/pci-cap-test/build.zig | 2 +- test/system/services/process-test/build.zig | 2 +- .../services/shared-memory-client/build.zig | 2 +- .../services/shared-memory-server/build.zig | 2 +- test/system/services/thread-test/build.zig | 2 +- test/system/services/vfs-test/build.zig | 2 +- 29 files changed, 53 insertions(+), 93 deletions(-) diff --git a/build-support/build.zig b/build-support/build.zig index bc1db57..d8ccdea 100644 --- a/build-support/build.zig +++ b/build-support/build.zig @@ -31,60 +31,20 @@ pub fn freestandingTarget(b: *std.Build) std.Build.ResolvedTarget { }); } -/// Which library domain package exports each importable module — the one -/// name -> home table. When a domain grows a module, it gets a row here; a -/// binary naming a module whose home is missing from its own build.zig.zon -/// fails loudly at dependency resolution. -const ModuleHome = struct { name: []const u8, home: []const u8 }; -const module_homes = [_]ModuleHome{ - // library/kernel — the userspace private-ABI library, split by concern. - .{ .name = "abi", .home = "kernel" }, - .{ .name = "system-call", .home = "kernel" }, - .{ .name = "ipc", .home = "kernel" }, - .{ .name = "time", .home = "kernel" }, - .{ .name = "thread", .home = "kernel" }, - .{ .name = "logging", .home = "kernel" }, - .{ .name = "process", .home = "kernel" }, - .{ .name = "file-system", .home = "kernel" }, - .{ .name = "memory", .home = "kernel" }, - .{ .name = "service", .home = "kernel" }, - .{ .name = "start", .home = "kernel" }, - // library/device — driver-side libraries + the flat reference data. - .{ .name = "mmio", .home = "device" }, - .{ .name = "acpi-ids", .home = "device" }, - .{ .name = "device-abi", .home = "device" }, - .{ .name = "aml", .home = "device" }, - .{ .name = "usb-abi", .home = "device" }, - .{ .name = "usb-ids", .home = "device" }, - .{ .name = "usb", .home = "device" }, - .{ .name = "driver", .home = "device" }, - .{ .name = "block", .home = "device" }, - .{ .name = "pci", .home = "device" }, - .{ .name = "pci-class", .home = "device" }, - .{ .name = "device-registry", .home = "device" }, - // library/client — userspace service clients. - .{ .name = "display-client", .home = "client" }, - .{ .name = "input-client", .home = "client" }, - // library/protocol — the wire protocols. - .{ .name = "vfs-protocol", .home = "protocol" }, - .{ .name = "input-protocol", .home = "protocol" }, - .{ .name = "block-protocol", .home = "protocol" }, - .{ .name = "usb-transfer-protocol", .home = "protocol" }, - .{ .name = "device-manager-protocol", .home = "protocol" }, - .{ .name = "display-protocol", .home = "protocol" }, - .{ .name = "scanout-protocol", .home = "protocol" }, - .{ .name = "power-protocol", .home = "protocol" }, - // library/csv — the /etc/*.csv helpers. - .{ .name = "csv", .home = "csv" }, - // library/xkeyboard-config — keycode -> keysym/character tables. - .{ .name = "xkeyboard-config", .home = "xkeyboard-config" }, -}; - -fn moduleHome(name: []const u8) ?[]const u8 { - for (module_homes) |entry| { - if (std.mem.eql(u8, entry.name, name)) return entry.home; +/// Resolve one imported module by searching the packages this binary DECLARED +/// in its own build.zig.zon — the C include path made literal: an import can +/// only be satisfied by a domain the binary claims, and each domain's own +/// build.zig (its addModule exports) is the single statement of who owns +/// what. There is no name table here to drift. +fn moduleFromDeclaredDependencies(b: *std.Build, name: []const u8) *std.Build.Module { + for (b.available_deps) |declared| { + const dependency = b.dependency(declared[0], .{}); + if (dependency.builder.modules.get(name)) |module| return module; } - return null; + @panic(b.fmt( + "no declared dependency exports a module named '{s}' — declare the domain that owns it in this package's build.zig.zon", + .{name}, + )); } /// What `userBinary` needs to know about one user binary. @@ -95,8 +55,8 @@ pub const UserBinaryOptions = struct { root_source_file: std.Build.LazyPath, /// Exactly the modules the program's source @imports (directly or through /// its same-directory files) — no more, no less. Order is free; sorted - /// reads best. An undeclared @import fails the compile; a declared name no - /// domain exports fails the build graph with a pointer to module_homes. + /// reads best. An undeclared @import fails the compile; a name no + /// declared domain exports fails the build graph, naming the miss. imports: []const []const u8, /// Built multi-threaded (`single_threaded = false`) so real atomics/TLS /// work — required before a binary may call `Thread.spawn` @@ -121,12 +81,10 @@ pub fn userBinary(b: *std.Build, options: UserBinaryOptions) *std.Build.Step.Com const kernel = b.dependency("kernel", .{}); var imports: std.ArrayListUnmanaged(std.Build.Module.Import) = .empty; for (options.imports) |name| { - const home = moduleHome(name) orelse @panic(b.fmt( - "no library domain exports a module named '{s}' — if a domain grew it, add its row to module_homes in build-support/build.zig", - .{name}, - )); - const dependency = if (std.mem.eql(u8, home, "kernel")) kernel else b.dependency(home, .{}); - imports.append(b.allocator, .{ .name = name, .module = dependency.module(name) }) catch @panic("OOM"); + imports.append(b.allocator, .{ + .name = name, + .module = moduleFromDeclaredDependencies(b, name), + }) catch @panic("OOM"); } // Settings (target, optimize, code model, ...) live on the root module // only; the program module inherits them. diff --git a/docs/build-packages-plan.md b/docs/build-packages-plan.md index 130f9a4..31b6b7f 100644 --- a/docs/build-packages-plan.md +++ b/docs/build-packages-plan.md @@ -62,8 +62,10 @@ Rules: include list — and its zon names only the domains those modules come from (plus `build-support` and `kernel`, which is implicit in every binary: the root shim and user link script live there). Nothing is pre-wired: an - undeclared `@import` is a compile error, and build-support's one - module-to-domain table (`module_homes`) resolves each name. Availability + undeclared `@import` is a compile error, and build-support resolves each + name by searching the packages the zon declares — the domains' own + addModule exports are the single statement of who owns what, with no name + table anywhere to drift. Availability never meant bloat — Zig only compiles what a program actually imports — but exactness makes the declared interface honest and machine-checked. - **Modules export source, not artifacts** — each consumer compiles libraries @@ -132,9 +134,9 @@ rewritten against the package template. ## Execution notes (the finished shape) - The shared recipe lives in `build-support/build.zig`: `userBinary` (what - every binary package calls, resolving each named import through the - `module_homes` table) and `programModule` (for per-binary addOptions - modules). The `start` root shim and `user.ld` are named through the kernel + every binary package calls; each named import resolves by searching the + packages the binary's zon declares) and `programModule` (for per-binary + addOptions modules). The `start` root shim and `user.ld` are named through the kernel package (Dependency.path). - Adding a binary = adding a directory with source + a ~15-line build.zig + zon (copy any existing binary package, e.g. diff --git a/system/drivers/pci-bus/build.zig b/system/drivers/pci-bus/build.zig index c8ad27a..f5bcad9 100644 --- a/system/drivers/pci-bus/build.zig +++ b/system/drivers/pci-bus/build.zig @@ -1,6 +1,6 @@ //! The pci-bus driver as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/system/drivers/ps2-bus/build.zig b/system/drivers/ps2-bus/build.zig index 05e2889..56733ae 100644 --- a/system/drivers/ps2-bus/build.zig +++ b/system/drivers/ps2-bus/build.zig @@ -1,6 +1,6 @@ //! The ps2-bus driver as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/system/drivers/usb-hid/build.zig b/system/drivers/usb-hid/build.zig index aac0f10..d8069d9 100644 --- a/system/drivers/usb-hid/build.zig +++ b/system/drivers/usb-hid/build.zig @@ -1,6 +1,6 @@ //! The usb-hid driver as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/system/drivers/usb-storage/build.zig b/system/drivers/usb-storage/build.zig index 2212815..ae8cb90 100644 --- a/system/drivers/usb-storage/build.zig +++ b/system/drivers/usb-storage/build.zig @@ -1,6 +1,6 @@ //! The usb-storage driver as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/system/drivers/usb-xhci-bus/build.zig b/system/drivers/usb-xhci-bus/build.zig index 5379364..773a3b4 100644 --- a/system/drivers/usb-xhci-bus/build.zig +++ b/system/drivers/usb-xhci-bus/build.zig @@ -1,6 +1,6 @@ //! The usb-xhci-bus driver as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/system/drivers/virtio-gpu/build.zig b/system/drivers/virtio-gpu/build.zig index f31b479..0d20b33 100644 --- a/system/drivers/virtio-gpu/build.zig +++ b/system/drivers/virtio-gpu/build.zig @@ -1,6 +1,6 @@ //! The virtio-gpu driver as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/system/services/acpi/build.zig b/system/services/acpi/build.zig index 94859f9..a2ce806 100644 --- a/system/services/acpi/build.zig +++ b/system/services/acpi/build.zig @@ -1,6 +1,6 @@ //! The acpi service as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. //! //! The artifact is named "discovery": one swappable process per firmware //! fills the ramdisk's neutral `discovery` slot (docs/discovery.md); the diff --git a/system/services/device-manager/build.zig b/system/services/device-manager/build.zig index 48a75e7..256f8d3 100644 --- a/system/services/device-manager/build.zig +++ b/system/services/device-manager/build.zig @@ -1,6 +1,6 @@ //! The device-manager service as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/system/services/display-demo/build.zig b/system/services/display-demo/build.zig index 2c74ccb..7d3f2e0 100644 --- a/system/services/display-demo/build.zig +++ b/system/services/display-demo/build.zig @@ -1,6 +1,6 @@ //! The display-demo service as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/system/services/display/build.zig b/system/services/display/build.zig index 600ae8e..7e32c5d 100644 --- a/system/services/display/build.zig +++ b/system/services/display/build.zig @@ -1,6 +1,6 @@ //! The display service as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/system/services/fat/build.zig b/system/services/fat/build.zig index 72d2fa8..5051929 100644 --- a/system/services/fat/build.zig +++ b/system/services/fat/build.zig @@ -1,6 +1,6 @@ //! The fat service as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/system/services/fdt/build.zig b/system/services/fdt/build.zig index 761617f..500df79 100644 --- a/system/services/fdt/build.zig +++ b/system/services/fdt/build.zig @@ -1,6 +1,6 @@ //! The fdt service as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. //! //! The artifact is named "discovery" like acpi's: the Raspberry Pis hand over //! a flattened device tree, and the aarch64 target flips the root's diff --git a/system/services/init/build.zig b/system/services/init/build.zig index 426dbdf..a27be23 100644 --- a/system/services/init/build.zig +++ b/system/services/init/build.zig @@ -1,6 +1,6 @@ //! init (PID 1) as a binary package (docs/build-packages-plan.md): this file //! names the binary and EXACTLY the modules its source imports — the shared -//! recipe and the module-to-domain map live in build-support. The root build +//! recipe resolves each name from the domains the zon declares. The root build //! consumes the artifact for the boot image and forwards its -Dserial here. const std = @import("std"); diff --git a/system/services/input/build.zig b/system/services/input/build.zig index 1568339..3e6756d 100644 --- a/system/services/input/build.zig +++ b/system/services/input/build.zig @@ -1,6 +1,6 @@ //! The input service as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/test/system/services/args-echo/build.zig b/test/system/services/args-echo/build.zig index 1582a92..4abe68b 100644 --- a/test/system/services/args-echo/build.zig +++ b/test/system/services/args-echo/build.zig @@ -1,6 +1,6 @@ //! The args-echo test fixture as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/test/system/services/crash-test/build.zig b/test/system/services/crash-test/build.zig index 2718e59..67f2380 100644 --- a/test/system/services/crash-test/build.zig +++ b/test/system/services/crash-test/build.zig @@ -1,6 +1,6 @@ //! The crash-test test fixture as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/test/system/services/device-list/build.zig b/test/system/services/device-list/build.zig index ae55e6e..0be8299 100644 --- a/test/system/services/device-list/build.zig +++ b/test/system/services/device-list/build.zig @@ -1,6 +1,6 @@ //! The device-list test fixture as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/test/system/services/fat-test/build.zig b/test/system/services/fat-test/build.zig index 3eabf74..15093d8 100644 --- a/test/system/services/fat-test/build.zig +++ b/test/system/services/fat-test/build.zig @@ -1,6 +1,6 @@ //! The fat-test test fixture as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/test/system/services/input-source/build.zig b/test/system/services/input-source/build.zig index 689c1f5..ef4cbf4 100644 --- a/test/system/services/input-source/build.zig +++ b/test/system/services/input-source/build.zig @@ -1,6 +1,6 @@ //! The input-source test fixture as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/test/system/services/input-test/build.zig b/test/system/services/input-test/build.zig index 0a3caa5..926fbd0 100644 --- a/test/system/services/input-test/build.zig +++ b/test/system/services/input-test/build.zig @@ -1,6 +1,6 @@ //! The input-test test fixture as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/test/system/services/iommu-fault-test/build.zig b/test/system/services/iommu-fault-test/build.zig index 0540549..b2e5450 100644 --- a/test/system/services/iommu-fault-test/build.zig +++ b/test/system/services/iommu-fault-test/build.zig @@ -1,6 +1,6 @@ //! The iommu-fault-test test fixture as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/test/system/services/pci-cap-test/build.zig b/test/system/services/pci-cap-test/build.zig index 4c7339d..e93f2cb 100644 --- a/test/system/services/pci-cap-test/build.zig +++ b/test/system/services/pci-cap-test/build.zig @@ -1,6 +1,6 @@ //! The pci-cap-test test fixture as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/test/system/services/process-test/build.zig b/test/system/services/process-test/build.zig index 62c861b..7f8b636 100644 --- a/test/system/services/process-test/build.zig +++ b/test/system/services/process-test/build.zig @@ -1,6 +1,6 @@ //! The process-test test fixture as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/test/system/services/shared-memory-client/build.zig b/test/system/services/shared-memory-client/build.zig index 26e6a50..a6a72b3 100644 --- a/test/system/services/shared-memory-client/build.zig +++ b/test/system/services/shared-memory-client/build.zig @@ -1,6 +1,6 @@ //! The shared-memory-client test fixture as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/test/system/services/shared-memory-server/build.zig b/test/system/services/shared-memory-server/build.zig index c821054..58c0dd9 100644 --- a/test/system/services/shared-memory-server/build.zig +++ b/test/system/services/shared-memory-server/build.zig @@ -1,6 +1,6 @@ //! The shared-memory-server test fixture as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/test/system/services/thread-test/build.zig b/test/system/services/thread-test/build.zig index 5261e44..8c5a368 100644 --- a/test/system/services/thread-test/build.zig +++ b/test/system/services/thread-test/build.zig @@ -1,6 +1,6 @@ //! The thread-test test fixture as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support"); diff --git a/test/system/services/vfs-test/build.zig b/test/system/services/vfs-test/build.zig index 76e3c41..05bafd1 100644 --- a/test/system/services/vfs-test/build.zig +++ b/test/system/services/vfs-test/build.zig @@ -1,6 +1,6 @@ //! The vfs-test test fixture as a binary package (docs/build-packages-plan.md): //! this file names the binary and EXACTLY the modules its source imports — -//! the shared recipe and the module-to-domain map live in build-support. +//! build-support resolves each name from the domains this zon declares. const std = @import("std"); const build_support = @import("build-support");