summaryrefslogtreecommitdiff
path: root/9proc/build.zig
diff options
context:
space:
mode:
Diffstat (limited to '9proc/build.zig')
-rw-r--r--9proc/build.zig169
1 files changed, 169 insertions, 0 deletions
diff --git a/9proc/build.zig b/9proc/build.zig
new file mode 100644
index 0000000..670ea27
--- /dev/null
+++ b/9proc/build.zig
@@ -0,0 +1,169 @@
+//! Build fragment for 9proc: the 9P debug/introspection library (module
+//! `9proc`), its freestanding check, the `9proc-demo` server and the
+//! test suites under 9proc/test. It is `@import`ed by the root build.zig
+//! and called with the root builder, so every `b.path(...)` here is relative
+//! to the cloud9 root (hence the `9proc/` prefix), every option is
+//! defined by the root (no `standardTargetOptions` here) and every step it
+//! registers lands in the root's step list under the `9proc` prefix.
+//!
+//! Steps: 9proc, 9proc-test, 9proc-check-freestanding,
+//! 9proc-debug-test, 9proc-debug-itest, 9proc-adv.
+const std = @import("std");
+
+/// What the root passes in. The root owns target/optimize resolution and the
+/// cloud9 module; this fragment derives everything else from them.
+pub const Context = struct {
+ target: std.Build.ResolvedTarget,
+ optimize: std.builtin.OptimizeMode,
+ /// The cloud9 library module for `target`. Its `root_source_file` is also
+ /// used to instantiate cloud9 for the freestanding check target.
+ cloud9: *std.Build.Module,
+};
+
+pub const Artifacts = struct {
+ /// The `9proc` module, exported with `b.addModule` so dependents of
+ /// cloud9 can `.module("9proc")`. Built for any target; the Linux
+ /// layer is compiled in only when the target OS is Linux.
+ module: *std.Build.Module,
+ /// The demo 9P2000 server (binary `9proc-demo`); null when the target is
+ /// not Linux. 9ns's integration tests use it as their server.
+ demo: ?*std.Build.Step.Compile,
+ /// `9proc-test`: library (and demo) unit tests.
+ test_step: *std.Build.Step,
+ /// `9proc-check-freestanding`: the core compiled for riscv32-freestanding-none.
+ check_step: *std.Build.Step,
+ /// `9proc-debug-test`: linux/debug.zig unit tests; null when not Linux.
+ debug_test_step: ?*std.Build.Step,
+ /// `9proc-adv`: the hostile-client suites are attached by `add`, the
+ /// Linux-layer suite (which needs a 9ns mount) by `addNsTests`.
+ adv_step: *std.Build.Step,
+};
+
+pub fn add(b: *std.Build, ctx: Context) Artifacts {
+ const target = ctx.target;
+ const optimize = ctx.optimize;
+ const is_linux = target.result.os.tag == .linux;
+
+ // Build-time facts embedded into the demo (/build/*): jj change id, UTC
+ // time, optimize mode, target triple. `jj` is pointed at the build root
+ // (the cloud9 checkout) explicitly, so the result does not depend on the
+ // directory `zig build` was invoked from.
+ const build_options = b.addOptions();
+ var code: u8 = 0;
+ const repo = b.build_root.path orelse ".";
+ const change_id = b.runAllowFail(&.{ "jj", "-R", repo, "log", "--no-graph", "-r", "@", "-T", "change_id.short()", "--ignore-working-copy" }, &code, .ignore) catch "unknown";
+ build_options.addOption([]const u8, "change_id", std.mem.trim(u8, change_id, " \n\r\t"));
+ const stamp = b.runAllowFail(&.{ "date", "-u", "+%Y-%m-%dT%H:%M:%SZ" }, &code, .ignore) catch "unknown";
+ build_options.addOption([]const u8, "build_time", std.mem.trim(u8, stamp, " \n\r\t"));
+ build_options.addOption([]const u8, "optimize", @tagName(optimize));
+ build_options.addOption([]const u8, "target", target.result.zigTriple(b.allocator) catch "unknown");
+
+ // The library: freestanding core + vars, scratch (allocator), Linux layer.
+ // Exported under the name `9proc` for packages that depend on cloud9.
+ const lib_mod = b.addModule("9proc", .{
+ .root_source_file = b.path("9proc/src/root.zig"),
+ .target = target,
+ .optimize = optimize,
+ .imports = &.{.{ .name = "cloud9", .module = ctx.cloud9 }},
+ });
+
+ const test_step = b.step("9proc-test", "Run the 9proc library's unit tests (and the demo's)");
+ test_step.dependOn(&b.addRunArtifact(b.addTest(.{ .root_module = lib_mod })).step);
+
+ // The core must compile without an OS (rule 1 of 9proc/docs/LIBRARY.md).
+ // cloud9 is re-instantiated for that target from the same root source.
+ const fs_target = b.resolveTargetQuery(.{ .cpu_arch = .riscv32, .os_tag = .freestanding, .abi = .none });
+ const fs_cloud9 = b.createModule(.{
+ .root_source_file = ctx.cloud9.root_source_file.?,
+ .target = fs_target,
+ .optimize = optimize,
+ });
+ const fs_check = b.addObject(.{
+ .name = "9proc-freestanding",
+ .root_module = b.createModule(.{
+ .root_source_file = b.path("9proc/src/freestanding_check.zig"),
+ .target = fs_target,
+ .optimize = optimize,
+ .imports = &.{.{ .name = "cloud9", .module = fs_cloud9 }},
+ }),
+ });
+ const check_step = b.step("9proc-check-freestanding", "Compile the 9proc core for riscv32-freestanding-none");
+ check_step.dependOn(&fs_check.step);
+
+ // `9proc-adv` exists on every target so the step list is stable; its
+ // suites are attached below (Linux only) and by addNsTests.
+ const adv_step = b.step("9proc-adv", "Run 9proc's adversarial suites (hostile clients, Linux layer; several minutes)");
+
+ if (!is_linux) {
+ adv_step.dependOn(&b.addFail("9proc-adv needs a Linux target (the demo server is Linux-only)").step);
+ return .{ .module = lib_mod, .demo = null, .test_step = test_step, .check_step = check_step, .debug_test_step = null, .adv_step = adv_step };
+ }
+
+ // The demo: a 9P2000 server whose tree is the binary itself (build-time,
+ // comptime and runtime facts, a worker thread, the Linux debug layer).
+ const demo_mod = b.createModule(.{
+ .root_source_file = b.path("9proc/demo/main.zig"),
+ .target = target,
+ .optimize = optimize,
+ .imports = &.{
+ .{ .name = "cloud9", .module = ctx.cloud9 },
+ .{ .name = "build_options", .module = build_options.createModule() },
+ .{ .name = "9proc", .module = lib_mod },
+ },
+ });
+ const demo = b.addExecutable(.{ .name = "9proc-demo", .root_module = demo_mod });
+ const install_demo = b.addInstallArtifact(demo, .{});
+ b.getInstallStep().dependOn(&install_demo.step);
+ b.step("9proc", "Build and install only the 9proc-demo server").dependOn(&install_demo.step);
+ test_step.dependOn(&b.addRunArtifact(b.addTest(.{ .root_module = demo_mod })).step);
+
+ // Linux debug facilities (threads, stacks, breakpoints, panic): self-contained unit tests.
+ const debug_mod = b.createModule(.{
+ .root_source_file = b.path("9proc/src/linux/debug.zig"),
+ .target = target,
+ .optimize = optimize,
+ });
+ const debug_test_step = b.step("9proc-debug-test", "Run the 9proc/src/linux/debug.zig unit tests");
+ debug_test_step.dependOn(&b.addRunArtifact(b.addTest(.{ .root_module = debug_mod })).step);
+
+ // Hostile raw-9P clients against the demo (framing, tags, floods; the core's
+ // /vars tree, snapshots, fid table). `--fast` as in the umbrella script.
+ inline for (.{ "adv_9proc_hostile", "adv_core_hostile" }) |suite| {
+ const run = b.addSystemCommand(&.{"bash"});
+ run.addFileArg(b.path("9proc/test/" ++ suite ++ ".sh"));
+ run.addArtifactArg(demo);
+ run.addArg("--fast");
+ adv_step.dependOn(&run.step);
+ }
+
+ return .{ .module = lib_mod, .demo = demo, .test_step = test_step, .check_step = check_step, .debug_test_step = debug_test_step, .adv_step = adv_step };
+}
+
+/// The suites that drive the demo through a 9ns mount: test/debug.sh
+/// (threads, stacks, breakpoints, panic end to end) and
+/// test/adv_linux_probe.sh (memory endpoints, signal machinery, poll loop).
+/// Called by the root after the 9ns fragment; `ns` is null when
+/// 9ns is disabled, in which case the steps exist but fail with a notice.
+/// Returns the `9proc-debug-itest` step (null when the target is not Linux).
+pub fn addNsTests(b: *std.Build, arts: Artifacts, ns: ?*std.Build.Step.Compile) ?*std.Build.Step {
+ const demo = arts.demo orelse return null; // not Linux: nothing to drive
+ const debug_itest = b.step("9proc-debug-itest", "Run 9proc/test/debug.sh (threads, stacks, breakpoints, panic through 9ns)");
+ const exe = ns orelse {
+ const fail = b.addFail("9proc-debug-itest and the Linux-layer adversarial suite need 9ns (build with -D9ns=true)");
+ debug_itest.dependOn(&fail.step);
+ arts.adv_step.dependOn(&fail.step);
+ return debug_itest;
+ };
+ const dbg = b.addSystemCommand(&.{"bash"});
+ dbg.addFileArg(b.path("9proc/test/debug.sh"));
+ dbg.addArtifactArg(exe);
+ dbg.addArtifactArg(demo);
+ debug_itest.dependOn(&dbg.step);
+
+ const adv_linux = b.addSystemCommand(&.{"bash"});
+ adv_linux.addFileArg(b.path("9proc/test/adv_linux_probe.sh"));
+ adv_linux.addArtifactArg(exe);
+ adv_linux.addArtifactArg(demo);
+ arts.adv_step.dependOn(&adv_linux.step);
+ return debug_itest;
+}