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,
|
threaded: bool = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Build one user binary against the domain packages' default import set —
|
/// THE default import set every user binary sees — the library/kernel concern
|
||||||
/// the library/kernel concern modules (ipc, memory, process, time, logging,
|
/// modules (ipc, memory, process, time, logging, file-system, ...), the
|
||||||
/// file-system, ...), the device/service clients (driver, block, display,
|
/// device/service clients (driver, block, display, input), mmio, acpi-ids,
|
||||||
/// input), mmio, acpi-ids, and xkeyboard-config. Per-binary extras go through
|
/// and xkeyboard-config — assembled from the domain packages. This is the
|
||||||
/// `programModule(exe).addImport`. This is THE recipe a binary package's
|
/// single authoritative list: the root build's stanzas and every binary
|
||||||
/// build.zig calls; the root shim and user link script come from the kernel
|
/// package both draw from here, so adding a default module is a one-place
|
||||||
/// domain package's directory.
|
/// change (the cross-cutting rule, docs/build-packages-plan.md).
|
||||||
pub fn userBinary(b: *std.Build, options: DomainUserBinaryOptions) *std.Build.Step.Compile {
|
pub fn defaultImports(libraries: Domains) [17]std.Build.Module.Import {
|
||||||
const kernel = options.domains.kernel;
|
const kernel = libraries.kernel;
|
||||||
const device = options.domains.device;
|
const device = libraries.device;
|
||||||
const client = options.domains.client;
|
const client = libraries.client;
|
||||||
const default_imports = [_]std.Build.Module.Import{
|
return .{
|
||||||
.{ .name = "mmio", .module = device.module("mmio") },
|
.{ .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 = "acpi-ids", .module = device.module("acpi-ids") },
|
||||||
.{ .name = "system-call", .module = kernel.module("system-call") },
|
.{ .name = "system-call", .module = kernel.module("system-call") },
|
||||||
.{ .name = "ipc", .module = kernel.module("ipc") },
|
.{ .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 = "display", .module = client.module("display") },
|
||||||
.{ .name = "input", .module = client.module("input") },
|
.{ .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, .{
|
return userBinaryFromImports(b, .{
|
||||||
.name = options.name,
|
.name = options.name,
|
||||||
.root_source_file = options.root_source_file,
|
.root_source_file = options.root_source_file,
|
||||||
.shim_source_file = kernel.path("root.zig"),
|
.shim_source_file = options.domains.kernel.path("root.zig"),
|
||||||
.linker_script = kernel.path("user.ld"),
|
.linker_script = options.domains.kernel.path("user.ld"),
|
||||||
.target = freestandingTarget(b),
|
.target = freestandingTarget(b),
|
||||||
.default_imports = &default_imports,
|
.default_imports = &default_imports,
|
||||||
.threaded = options.threaded,
|
.threaded = options.threaded,
|
||||||
|
|||||||
@@ -86,11 +86,14 @@ fn addUserBinaryImpl(
|
|||||||
root: []const u8,
|
root: []const u8,
|
||||||
threaded: bool,
|
threaded: bool,
|
||||||
) *std.Build.Step.Compile {
|
) *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, .{
|
return build_support.userBinaryFromImports(b, .{
|
||||||
.name = name,
|
.name = name,
|
||||||
.root_source_file = b.path(root),
|
.root_source_file = b.path(root),
|
||||||
.shim_source_file = b.path("library/kernel/root.zig"),
|
.shim_source_file = kernel_library.path("root.zig"),
|
||||||
.linker_script = b.path("library/kernel/user.ld"),
|
.linker_script = kernel_library.path("user.ld"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.default_imports = default_imports,
|
.default_imports = default_imports,
|
||||||
.threaded = threaded,
|
.threaded = threaded,
|
||||||
@@ -251,7 +254,6 @@ pub fn build(b: *std.Build) void {
|
|||||||
const csv_module = csv_library.module("csv");
|
const csv_module = csv_library.module("csv");
|
||||||
const device_registry_module = device_library.module("device-registry");
|
const device_registry_module = device_library.module("device-registry");
|
||||||
const aml_module = device_library.module("aml");
|
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_abi_module = device_library.module("usb-abi");
|
||||||
const usb_ids_module = device_library.module("usb-ids");
|
const usb_ids_module = device_library.module("usb-ids");
|
||||||
const usb_transfer_protocol_module = protocol_library.module("usb-transfer-protocol");
|
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 scanout_protocol_module = protocol_library.module("scanout-protocol");
|
||||||
const power_protocol_module = protocol_library.module("power-protocol");
|
const power_protocol_module = protocol_library.module("power-protocol");
|
||||||
|
|
||||||
// The library/kernel concern modules (the userspace private-ABI library),
|
// The driver-side libraries some binaries name as per-binary extras. (The
|
||||||
// the device-domain driver libraries, and the service clients.
|
// rest of the domain modules reach the root only through build-support's
|
||||||
const mmio_module = device_library.module("mmio");
|
// defaultImports below.)
|
||||||
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");
|
|
||||||
const pci_module = device_library.module("pci");
|
const pci_module = device_library.module("pci");
|
||||||
const usb_module = device_library.module("usb");
|
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 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
|
// 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);
|
b.getInstallStep().dependOn(&kernel_install.step);
|
||||||
|
|
||||||
// --- init: the first user-space program (a system service) ---
|
// --- init: the first user-space program (a system service) ---
|
||||||
// The default module set every user binary can import directly: the library/kernel
|
// The default module set every user binary can import directly, drawn from
|
||||||
// concern modules, the device/service clients, mmio, the keyboard layouts, and the ACPI
|
// build-support's single authoritative list so the root stanzas and the
|
||||||
// id registry. Per-binary extras are added with programModule(exe).addImport.
|
// binary packages can never drift apart. Per-binary extras are added with
|
||||||
const default_imports = [_]std.Build.Module.Import{
|
// programModule(exe).addImport.
|
||||||
.{ .name = "mmio", .module = mmio_module },
|
const default_imports = build_support.defaultImports(.{
|
||||||
.{ .name = "xkeyboard-config", .module = xkeyboard_config_module },
|
.kernel = kernel_library,
|
||||||
.{ .name = "acpi-ids", .module = acpi_ids_module },
|
.device = device_library,
|
||||||
.{ .name = "system-call", .module = system_call_module },
|
.client = client_library,
|
||||||
.{ .name = "ipc", .module = ipc_module },
|
.xkeyboard_config = xkeyboard_config_library,
|
||||||
.{ .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 },
|
|
||||||
};
|
|
||||||
|
|
||||||
// Built by the shared user-binary recipe (see addUserBinary): freestanding,
|
// Built by the shared user-binary recipe (see addUserBinary): freestanding,
|
||||||
// linked into the kernel's user region against the library/kernel modules, and
|
// 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/boot-handoff.zig",
|
||||||
"system/abi.zig",
|
"system/abi.zig",
|
||||||
"system/initial-ramdisk.zig", // v2 path-named entries: find/basename/magic
|
"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/scancode.zig", // set-2 decode + keyboard state machine
|
||||||
"system/drivers/ps2-bus/mouse-packet.zig", // 3-byte mouse packet assembly
|
"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-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/bulk-only-transport.zig", // CBW/CSW wrapper sizes
|
||||||
"system/drivers/usb-storage/scsi.zig", // SCSI CDB encodings (big-endian)
|
"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/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/fat/engine.zig", // FAT read/write over a RAM-backed image
|
||||||
"system/services/display/compositor.zig", // Rect math + fill/composite/blit-tile
|
"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-gpu-protocol.zig", // virtio-gpu command struct sizes
|
||||||
"system/drivers/virtio-gpu/virtio-pci.zig", // virtio 1.0 PCI transport struct sizes
|
"system/drivers/virtio-gpu/virtio-pci.zig", // virtio 1.0 PCI transport struct sizes
|
||||||
}) |root| {
|
}) |root| {
|
||||||
@@ -904,33 +868,21 @@ pub fn build(b: *std.Build) void {
|
|||||||
test_step.dependOn(&b.addRunArtifact(mod_tests).step);
|
test_step.dependOn(&b.addRunArtifact(mod_tests).step);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The device registry imports the shared `csv` module, so its tests need that
|
// The library domains own their unit tests (each package's standalone
|
||||||
// import wired and don't fit the plain loop above. These prove the /etc/devices.csv
|
// `zig build test` step); the root aggregate delegates to those steps so
|
||||||
// parse + most-specific driver match (incl. virtio 1AF4:1050 beating a class rule).
|
// one command still runs everything and a test added inside a domain
|
||||||
const device_registry_tests = b.addTest(.{
|
// package can never be silently skipped here. Domain tests are host-only,
|
||||||
.root_module = b.createModule(.{
|
// so root's -Dtarget/-Doptimize deliberately do not reach them.
|
||||||
.root_source_file = b.path("library/device/registry/device-registry.zig"),
|
for ([_]*std.Build.Dependency{
|
||||||
.target = target,
|
kernel_library,
|
||||||
.optimize = optimize,
|
device_library,
|
||||||
.imports = &.{.{ .name = "csv", .module = csv_module }},
|
client_library,
|
||||||
}),
|
protocol_library,
|
||||||
});
|
csv_library,
|
||||||
test_step.dependOn(&b.addRunArtifact(device_registry_tests).step);
|
xkeyboard_config_library,
|
||||||
|
}) |library| {
|
||||||
// The xkeyboard-config keymap tests need its generated `layouts` import wired, so they
|
test_step.dependOn(&library.builder.top_level_steps.get("test").?.step);
|
||||||
// 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 tagged kernel log ring: append/wrap/reclaim/sequence-gap behavior over
|
// 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
|
// 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);
|
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
|
// Convenience: `zig build gen-xkeyboard-config` regenerates the layout tables from the
|
||||||
// vendored data (offline). `fetch` (the network step) stays a manual script run.
|
// vendored data (offline). `fetch` (the network step) stays a manual script run.
|
||||||
const gen_xkb = b.addSystemCommand(&.{ "python3", "tools/make-xkeyboard-config.py", "generate" });
|
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") },
|
.{ .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