summaryrefslogtreecommitdiff
path: root/9player/build.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-19 21:26:05 -0300
committerGabriel Schneider <[email protected]>2026-09-19 21:26:05 -0300
commitb05abcba3ea09ea106ad28364c6e40a3ec31b890 (patch)
tree9170fac5e7e5d8bde108de34a182aaa9d6844117 /9player/build.zig
parentae310a207534b33b7321dd2b9f423a73b1969159 (diff)
downloadcloud9-b05abcba3ea09ea106ad28364c6e40a3ec31b890.tar.gz
cloud9-b05abcba3ea09ea106ad28364c6e40a3ec31b890.zip
Add 9player and introspect as programs beside the library
9player/: FUSE mount CLI that mounts a 9P2000 tree into a fresh user+mount namespace and runs a program in it (no root, no libfuse, no libc). introspect/: the 9P debug/introspection library (freestanding core, value renderers, Linux probe with threads/stacks/memory/breakpoints/panics) and its demo server. Each has its own build fragment; the root build.zig wires them behind -D9player/-Dintrospect with namespaced steps (9player-itest, introspect-check-freestanding, programs-test, ...) and exports the introspect module for dependents. This is the layout for related programs. Co-Authored-By: Claude Fable 5.1 <[email protected]>
Diffstat (limited to '9player/build.zig')
-rw-r--r--9player/build.zig71
1 files changed, 71 insertions, 0 deletions
diff --git a/9player/build.zig b/9player/build.zig
new file mode 100644
index 0000000..f3d5c1b
--- /dev/null
+++ b/9player/build.zig
@@ -0,0 +1,71 @@
+//! Build fragment for 9player: mount a 9P2000 tree into a fresh mount
+//! namespace via FUSE and run a program in it (Linux only, no libc). 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
+//! `9player/` 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 `9player` prefix.
+//!
+//! Steps: 9player, 9player-test, 9player-itest, 9player-adv.
+const std = @import("std");
+
+/// What the root passes in. The root owns target/optimize resolution and the
+/// cloud9 module; the integration suites also need a 9P server to mount,
+/// which is the introspect demo built by the sibling fragment.
+pub const Context = struct {
+ target: std.Build.ResolvedTarget,
+ optimize: std.builtin.OptimizeMode,
+ cloud9: *std.Build.Module,
+ /// The `introspect` demo server; null when introspect is disabled, in
+ /// which case the end-to-end steps exist but fail with a notice.
+ introspect_demo: ?*std.Build.Step.Compile,
+};
+
+pub const Artifacts = struct {
+ /// The 9player executable (also installed by the plain `zig build`).
+ exe: *std.Build.Step.Compile,
+ /// `9player-test`, `9player-itest`, `9player-adv`.
+ test_step: *std.Build.Step,
+ itest_step: *std.Build.Step,
+ adv_step: *std.Build.Step,
+};
+
+pub fn add(b: *std.Build, ctx: Context) Artifacts {
+ const target = ctx.target;
+ const optimize = ctx.optimize;
+ std.debug.assert(target.result.os.tag == .linux); // the root only enables 9player on Linux
+
+ const player_mod = b.createModule(.{
+ .root_source_file = b.path("9player/src/main.zig"),
+ .target = target,
+ .optimize = optimize,
+ .imports = &.{.{ .name = "cloud9", .module = ctx.cloud9 }},
+ });
+ const player = b.addExecutable(.{ .name = "9player", .root_module = player_mod });
+ const install = b.addInstallArtifact(player, .{});
+ b.getInstallStep().dependOn(&install.step);
+ b.step("9player", "Build and install only the 9player binary").dependOn(&install.step);
+
+ // Unit tests: protocol structs, session, bridge, namespace helpers (main.zig
+ // reaches every module).
+ const test_step = b.step("9player-test", "Run 9player's unit tests");
+ test_step.dependOn(&b.addRunArtifact(b.addTest(.{ .root_module = player_mod })).step);
+
+ // End-to-end suites: real namespaces, real FUSE, a real 9P server.
+ const itest = b.step("9player-itest", "Run 9player/test/integration.sh (needs unprivileged user namespaces and /dev/fuse)");
+ const adv = b.step("9player-adv", "Run 9player/test/adversarial.sh (hostile servers, namespaces, stress; several minutes)");
+ const demo = ctx.introspect_demo orelse {
+ const fail = b.addFail("9player-itest and 9player-adv need the introspect demo server (build with -Dintrospect=true)");
+ itest.dependOn(&fail.step);
+ adv.dependOn(&fail.step);
+ return .{ .exe = player, .test_step = test_step, .itest_step = itest, .adv_step = adv };
+ };
+ inline for (.{ .{ itest, "integration" }, .{ adv, "adversarial" } }) |pair| {
+ const run = b.addSystemCommand(&.{"bash"});
+ run.addFileArg(b.path("9player/test/" ++ pair[1] ++ ".sh"));
+ run.addArtifactArg(player);
+ run.addArtifactArg(demo);
+ pair[0].dependOn(&run.step);
+ }
+ return .{ .exe = player, .test_step = test_step, .itest_step = itest, .adv_step = adv };
+}