build: single-source the default import set; delegate library tests
Review findings from the pilot: the 17-module default import set was maintained twice (root's array and build-support's userBinary) — drift would silently make packaged binaries differ from root-built ones. It now lives once, as build-support.defaultImports; root and userBinary both draw from it, and root's user-binary wrapper names the shim + link script through the kernel package like build-support does. The root aggregate test step likewise duplicated the library domains' 14 test definitions; it now depends on each domain's own standalone test step (host-only, so root's -Dtarget/-Doptimize deliberately do not reach them), and the client domain gains an empty test step for uniformity. Boot-image file list unchanged.
This commit is contained in:
+24
-15
@@ -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,
|
||||
|
||||
@@ -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" });
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user