diff --git a/build-support/build.zig b/build-support/build.zig index 474c9b0..597486f 100644 --- a/build-support/build.zig +++ b/build-support/build.zig @@ -148,20 +148,20 @@ pub const DomainUserBinaryOptions = struct { threaded: bool = false, }; -/// Build one user binary against the domain packages' default import set — -/// the library/kernel concern modules (ipc, memory, process, time, logging, -/// file-system, ...), the device/service clients (driver, block, display, -/// input), mmio, acpi-ids, and xkeyboard-config. Per-binary extras go through -/// `programModule(exe).addImport`. This is THE recipe a binary package's -/// build.zig calls; the root shim and user link script come from the kernel -/// domain package's directory. -pub fn userBinary(b: *std.Build, options: DomainUserBinaryOptions) *std.Build.Step.Compile { - const kernel = options.domains.kernel; - const device = options.domains.device; - const client = options.domains.client; - const default_imports = [_]std.Build.Module.Import{ +/// THE default import set every user binary sees — the library/kernel concern +/// modules (ipc, memory, process, time, logging, file-system, ...), the +/// device/service clients (driver, block, display, input), mmio, acpi-ids, +/// and xkeyboard-config — assembled from the domain packages. This is the +/// single authoritative list: the root build's stanzas and every binary +/// package both draw from here, so adding a default module is a one-place +/// change (the cross-cutting rule, docs/build-packages-plan.md). +pub fn defaultImports(libraries: Domains) [17]std.Build.Module.Import { + const kernel = libraries.kernel; + const device = libraries.device; + const client = libraries.client; + return .{ .{ .name = "mmio", .module = device.module("mmio") }, - .{ .name = "xkeyboard-config", .module = options.domains.xkeyboard_config.module("xkeyboard-config") }, + .{ .name = "xkeyboard-config", .module = libraries.xkeyboard_config.module("xkeyboard-config") }, .{ .name = "acpi-ids", .module = device.module("acpi-ids") }, .{ .name = "system-call", .module = kernel.module("system-call") }, .{ .name = "ipc", .module = kernel.module("ipc") }, @@ -178,11 +178,20 @@ pub fn userBinary(b: *std.Build, options: DomainUserBinaryOptions) *std.Build.St .{ .name = "display", .module = client.module("display") }, .{ .name = "input", .module = client.module("input") }, }; +} + +/// Build one user binary against the domain packages' default import set +/// (`defaultImports`). Per-binary extras go through +/// `programModule(exe).addImport`. This is THE recipe a binary package's +/// build.zig calls; the root shim and user link script come from the kernel +/// domain package's directory. +pub fn userBinary(b: *std.Build, options: DomainUserBinaryOptions) *std.Build.Step.Compile { + const default_imports = defaultImports(options.domains); return userBinaryFromImports(b, .{ .name = options.name, .root_source_file = options.root_source_file, - .shim_source_file = kernel.path("root.zig"), - .linker_script = kernel.path("user.ld"), + .shim_source_file = options.domains.kernel.path("root.zig"), + .linker_script = options.domains.kernel.path("user.ld"), .target = freestandingTarget(b), .default_imports = &default_imports, .threaded = options.threaded, diff --git a/build.zig b/build.zig index d05f904..026e140 100644 --- a/build.zig +++ b/build.zig @@ -86,11 +86,14 @@ fn addUserBinaryImpl( root: []const u8, threaded: bool, ) *std.Build.Step.Compile { + // The shim and link script live in the kernel domain package, so name them + // through it — the same spelling build-support's userBinary uses. + const kernel_library = b.dependency("kernel", .{}); return build_support.userBinaryFromImports(b, .{ .name = name, .root_source_file = b.path(root), - .shim_source_file = b.path("library/kernel/root.zig"), - .linker_script = b.path("library/kernel/user.ld"), + .shim_source_file = kernel_library.path("root.zig"), + .linker_script = kernel_library.path("user.ld"), .target = target, .default_imports = default_imports, .threaded = threaded, @@ -251,7 +254,6 @@ pub fn build(b: *std.Build) void { const csv_module = csv_library.module("csv"); const device_registry_module = device_library.module("device-registry"); const aml_module = device_library.module("aml"); - const acpi_ids_module = device_library.module("acpi-ids"); const usb_abi_module = device_library.module("usb-abi"); const usb_ids_module = device_library.module("usb-ids"); const usb_transfer_protocol_module = protocol_library.module("usb-transfer-protocol"); @@ -305,27 +307,11 @@ pub fn build(b: *std.Build) void { const scanout_protocol_module = protocol_library.module("scanout-protocol"); const power_protocol_module = protocol_library.module("power-protocol"); - // The library/kernel concern modules (the userspace private-ABI library), - // the device-domain driver libraries, and the service clients. - const mmio_module = device_library.module("mmio"); - const system_call_module = kernel_library.module("system-call"); - const ipc_module = kernel_library.module("ipc"); - const time_module = kernel_library.module("time"); - const thread_module = kernel_library.module("thread"); - const logging_module = kernel_library.module("logging"); - const process_module = kernel_library.module("process"); - const file_system_module = kernel_library.module("file-system"); - const memory_module = kernel_library.module("memory"); - const service_module = kernel_library.module("service"); - const start_module = kernel_library.module("start"); - const driver_module = device_library.module("driver"); - const block_client_module = device_library.module("block"); - const display_client_module = client_library.module("display"); - const input_client_module = client_library.module("input"); + // The driver-side libraries some binaries name as per-binary extras. (The + // rest of the domain modules reach the root only through build-support's + // defaultImports below.) const pci_module = device_library.module("pci"); const usb_module = device_library.module("usb"); - const xkb_layouts_module = xkeyboard_config_library.module("layouts"); - const xkeyboard_config_module = xkeyboard_config_library.module("xkeyboard-config"); // The initial_ramdisk container format, shared by the kernel (unpacks it) and // the EFI loader (packs it in RAM from the boot volume's /system tree). No @@ -373,28 +359,16 @@ pub fn build(b: *std.Build) void { b.getInstallStep().dependOn(&kernel_install.step); // --- init: the first user-space program (a system service) --- - // The default module set every user binary can import directly: the library/kernel - // concern modules, the device/service clients, mmio, the keyboard layouts, and the ACPI - // id registry. Per-binary extras are added with programModule(exe).addImport. - const default_imports = [_]std.Build.Module.Import{ - .{ .name = "mmio", .module = mmio_module }, - .{ .name = "xkeyboard-config", .module = xkeyboard_config_module }, - .{ .name = "acpi-ids", .module = acpi_ids_module }, - .{ .name = "system-call", .module = system_call_module }, - .{ .name = "ipc", .module = ipc_module }, - .{ .name = "memory", .module = memory_module }, - .{ .name = "process", .module = process_module }, - .{ .name = "thread", .module = thread_module }, - .{ .name = "time", .module = time_module }, - .{ .name = "logging", .module = logging_module }, - .{ .name = "file-system", .module = file_system_module }, - .{ .name = "service", .module = service_module }, - .{ .name = "start", .module = start_module }, - .{ .name = "driver", .module = driver_module }, - .{ .name = "block", .module = block_client_module }, - .{ .name = "display", .module = display_client_module }, - .{ .name = "input", .module = input_client_module }, - }; + // The default module set every user binary can import directly, drawn from + // build-support's single authoritative list so the root stanzas and the + // binary packages can never drift apart. Per-binary extras are added with + // programModule(exe).addImport. + const default_imports = build_support.defaultImports(.{ + .kernel = kernel_library, + .device = device_library, + .client = client_library, + .xkeyboard_config = xkeyboard_config_library, + }); // Built by the shared user-binary recipe (see addUserBinary): freestanding, // linked into the kernel's user region against the library/kernel modules, and @@ -873,24 +847,14 @@ pub fn build(b: *std.Build) void { "system/boot-handoff.zig", "system/abi.zig", "system/initial-ramdisk.zig", // v2 path-named entries: find/basename/magic - "library/device/model/device-abi.zig", - "library/device/pci/pci-class.zig", // class/subclass/prog-IF name decoding - "library/device/acpi/acpi-ids.zig", // _HID name decoding - "library/device/acpi/aml/aml.zig", // AML parse + interpret, incl. Notify dispatch (M21) - "library/device/usb/usb-abi.zig", // wire sizes + bit packings + set-up packet encodings - "library/device/usb/usb-ids.zig", // class/subclass/protocol code assignments - "library/csv/csv.zig", // shared /etc/*.csv comment-strip + field-split helpers - "library/device/mmio/mmio.zig", // barriers assemble + registers round-trip "system/drivers/ps2-bus/scancode.zig", // set-2 decode + keyboard state machine "system/drivers/ps2-bus/mouse-packet.zig", // 3-byte mouse packet assembly "system/drivers/usb-hid/hid-report.zig", // HID boot-report keyboard/mouse decode "system/drivers/usb-storage/bulk-only-transport.zig", // CBW/CSW wrapper sizes "system/drivers/usb-storage/scsi.zig", // SCSI CDB encodings (big-endian) - "library/protocol/vfs/vfs-protocol.zig", // NodeKind / DirectoryEntry sizes + op values "system/services/fat/on-disk.zig", // FAT on-disk struct sizes + type detection "system/services/fat/engine.zig", // FAT read/write over a RAM-backed image "system/services/display/compositor.zig", // Rect math + fill/composite/blit-tile - "library/protocol/display/display-protocol.zig", // pack(): native pixel encoding per format "system/drivers/virtio-gpu/virtio-gpu-protocol.zig", // virtio-gpu command struct sizes "system/drivers/virtio-gpu/virtio-pci.zig", // virtio 1.0 PCI transport struct sizes }) |root| { @@ -904,33 +868,21 @@ pub fn build(b: *std.Build) void { test_step.dependOn(&b.addRunArtifact(mod_tests).step); } - // The device registry imports the shared `csv` module, so its tests need that - // import wired and don't fit the plain loop above. These prove the /etc/devices.csv - // parse + most-specific driver match (incl. virtio 1AF4:1050 beating a class rule). - const device_registry_tests = b.addTest(.{ - .root_module = b.createModule(.{ - .root_source_file = b.path("library/device/registry/device-registry.zig"), - .target = target, - .optimize = optimize, - .imports = &.{.{ .name = "csv", .module = csv_module }}, - }), - }); - test_step.dependOn(&b.addRunArtifact(device_registry_tests).step); - - // The xkeyboard-config keymap tests need its generated `layouts` import wired, so they - // don't fit the plain loop above. Its keycode->character assertions are the end-to-end - // proof that the xkb-data -> generator -> Zig-lookup pipeline is correct. - const xkb_tests = b.addTest(.{ - .root_module = b.createModule(.{ - .root_source_file = b.path("library/xkeyboard-config/xkeyboard-config.zig"), - .target = target, - .optimize = optimize, - .imports = &.{ - .{ .name = "layouts", .module = xkb_layouts_module }, - }, - }), - }); - test_step.dependOn(&b.addRunArtifact(xkb_tests).step); + // The library domains own their unit tests (each package's standalone + // `zig build test` step); the root aggregate delegates to those steps so + // one command still runs everything and a test added inside a domain + // package can never be silently skipped here. Domain tests are host-only, + // so root's -Dtarget/-Doptimize deliberately do not reach them. + for ([_]*std.Build.Dependency{ + kernel_library, + device_library, + client_library, + protocol_library, + csv_library, + xkeyboard_config_library, + }) |library| { + test_step.dependOn(&library.builder.top_level_steps.get("test").?.step); + } // The tagged kernel log ring: append/wrap/reclaim/sequence-gap behavior over // a RAM buffer. Needs the `abi` module (record header layout), so it doesn't @@ -947,37 +899,6 @@ pub fn build(b: *std.Build) void { }); test_step.dependOn(&b.addRunArtifact(log_ring_tests).step); - // runtime.time's Instant/Duration arithmetic. time.zig pulls in system.zig (the - // syscall wrappers), which needs the `abi` module, so it doesn't fit the plain - // loop above. - const time_tests = b.addTest(.{ - .root_module = b.createModule(.{ - .root_source_file = b.path("library/kernel/time.zig"), - .target = target, - .optimize = optimize, - .imports = &.{ - .{ .name = "abi", .module = abi_module }, - }, - }), - }); - test_step.dependOn(&b.addRunArtifact(time_tests).step); - - // runtime.Thread's lock/condvar state machines (Mutex/Condition/RwLock/WaitGroup). Its - // Futex seam falls back to std.Thread.Futex off the danos target, so the tests exercise - // them with real host threads (docs/threading-plan.md M11). Like time.zig it pulls in - // system.zig (syscall wrappers), which needs the `abi` module. - const thread_tests = b.addTest(.{ - .root_module = b.createModule(.{ - .root_source_file = b.path("library/kernel/thread.zig"), - .target = target, - .optimize = optimize, - .imports = &.{ - .{ .name = "abi", .module = abi_module }, - }, - }), - }); - test_step.dependOn(&b.addRunArtifact(thread_tests).step); - // Convenience: `zig build gen-xkeyboard-config` regenerates the layout tables from the // vendored data (offline). `fetch` (the network step) stays a manual script run. const gen_xkb = b.addSystemCommand(&.{ "python3", "tools/make-xkeyboard-config.py", "generate" }); diff --git a/library/client/build.zig b/library/client/build.zig index ca20b20..ed6420c 100644 --- a/library/client/build.zig +++ b/library/client/build.zig @@ -26,4 +26,10 @@ pub fn build(b: *std.Build) void { .{ .name = "input-protocol", .module = protocol.module("input-protocol") }, }, }); + + // Standalone `zig build test`, kept for uniformity across the domains (the + // root aggregate depends on every domain's test step). The clients have no + // host-runnable unit tests yet — they are thin IPC conversation wrappers — + // so the step is empty until one grows some. + _ = b.step("test", "Run the client unit tests (none yet)"); }