-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathbuild.zig
More file actions
210 lines (188 loc) · 8.67 KB
/
build.zig
File metadata and controls
210 lines (188 loc) · 8.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
const std = @import("std");
const builtin = @import("builtin");
pub fn build(b: *std.Build) void {
const optimize = b.standardOptimizeOption(.{});
const options = b.addOptions();
const fail_loudly = b.option(bool, "fail-loudly", "crash immediately on unsupported syscall") orelse false;
options.addOption(bool, "fail_loudly", fail_loudly);
// for run-node only
const interactive = b.option(bool, "interactive", "run-node: boot into interactive REPL") orelse false;
const LogLevel = enum { off, debug };
const log_level = b.option(LogLevel, "log-level", "run-node: log level for the sandbox") orelse .debug;
// Callers can select an architecture to target
// It defaults to the host architecture
const Arch = enum { aarch64, x86_64 };
const arch_arg = b.option(Arch, "arch", "Architecture for Docker run/test (default: host)") orelse switch (builtin.cpu.arch) {
.aarch64 => .aarch64,
.x86_64 => .x86_64,
else => @compileError("unsupported host architecture"),
};
const arch: std.Target.Cpu.Arch = switch (arch_arg) {
.aarch64 => .aarch64,
.x86_64 => .x86_64,
};
const bin_suffix: []const u8 = switch (arch_arg) {
.aarch64 => "-aarch64",
.x86_64 => "-x86_64",
};
const targets = [_]struct {
cpu_arch: std.Target.Cpu.Arch,
suffix: []const u8,
}{
.{ .cpu_arch = .aarch64, .suffix = "-aarch64" },
.{ .cpu_arch = .x86_64, .suffix = "-x86_64" },
};
// Build node bindings library for each platform
const node_api = b.dependency("node_api", .{});
const node_platforms = [_]struct {
cpu_arch: std.Target.Cpu.Arch,
abi: std.Target.Abi,
dest_dir: []const u8,
}{
.{ .cpu_arch = .aarch64, .abi = .musl, .dest_dir = "../src/sdks/node/platforms/linux-arm64-musl" },
.{ .cpu_arch = .aarch64, .abi = .gnu, .dest_dir = "../src/sdks/node/platforms/linux-arm64-gnu" },
.{ .cpu_arch = .x86_64, .abi = .musl, .dest_dir = "../src/sdks/node/platforms/linux-x64-musl" },
.{ .cpu_arch = .x86_64, .abi = .gnu, .dest_dir = "../src/sdks/node/platforms/linux-x64-gnu" },
};
var node_installs: [node_platforms.len]*std.Build.Step = undefined;
var arch_node_installs: [node_platforms.len]*std.Build.Step = undefined;
var arch_node_count: usize = 0;
for (node_platforms, 0..) |platform, i| {
const target = b.resolveTargetQuery(.{
.cpu_arch = platform.cpu_arch,
.os_tag = .linux,
.abi = platform.abi,
});
const core_module = b.createModule(.{
.root_source_file = b.path("src/core/root.zig"),
.target = target,
.optimize = optimize,
});
// Add config module to enable fail-loudly from core
core_module.addOptions("config", options);
const node_lib = b.addLibrary(.{
.name = "libbvisor",
.linkage = .dynamic,
.root_module = b.createModule(.{
.root_source_file = b.path("src/sdks/node/zig/root.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
}),
});
node_lib.root_module.addImport("core", core_module);
node_lib.root_module.addIncludePath(node_api.path("include"));
node_lib.linker_allow_shlib_undefined = true;
const install = b.addInstallArtifact(node_lib, .{
.dest_dir = .{ .override = .{ .custom = platform.dest_dir } },
.dest_sub_path = "libbvisor.node",
});
b.getInstallStep().dependOn(&install.step);
node_installs[i] = &install.step;
if (platform.cpu_arch == arch) {
arch_node_installs[arch_node_count] = &install.step;
arch_node_count += 1;
}
}
// Build exe and test binaries for both architectures
var exe_install_step: ?*std.Build.Step = null;
var test_install_step: ?*std.Build.Step = null;
for (targets) |t| {
const linux_target = b.resolveTargetQuery(.{
.cpu_arch = t.cpu_arch,
.os_tag = .linux,
.abi = .musl,
});
const linux_exe = b.addExecutable(.{
.name = "bVisor",
.root_module = b.createModule(.{
.root_source_file = b.path("src/core/main.zig"),
.target = linux_target,
.optimize = optimize,
}),
});
// Add config module to enable fail-loudly
linux_exe.root_module.addOptions("config", options);
const exe_install = b.addInstallArtifact(linux_exe, .{
.dest_sub_path = b.fmt("bVisor{s}", .{t.suffix}),
});
b.getInstallStep().dependOn(&exe_install.step);
if (t.cpu_arch == arch) exe_install_step = &exe_install.step;
const linux_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path("src/core/main.zig"),
.target = linux_target,
.optimize = optimize,
}),
});
const test_install = b.addInstallArtifact(linux_tests, .{
.dest_sub_path = b.fmt("tests{s}", .{t.suffix}),
});
b.getInstallStep().dependOn(&test_install.step);
if (t.cpu_arch == arch) test_install_step = &test_install.step;
}
std.debug.assert(exe_install_step != null);
std.debug.assert(test_install_step != null);
// 'run' executes the sandbox in a Linux container
// Seccomp does not work cross-architecture due to the emulation layer
const run_cli_step = b.step("run", "Run executable in a Linux container");
if (arch != builtin.cpu.arch) {
run_cli_step.dependOn(&b.addFail("zig build run requires native arch (seccomp does not work under emulation)").step);
} else {
const run_cmd = b.addSystemCommand(&.{ "docker", "run", "--rm", "--security-opt", "seccomp=unconfined" });
run_cmd.addArgs(&.{ "-v", "./zig-out:/zig-out", "alpine" });
run_cmd.addArg(b.fmt("/zig-out/bin/bVisor{s}", .{bin_suffix}));
run_cmd.step.dependOn(exe_install_step.?);
run_cli_step.dependOn(&run_cmd.step);
}
// 'test' runs unit tests in a Linux container
const test_cli_step = b.step("test", "Run unit tests in Docker container");
const docker_test_cmd = b.addSystemCommand(&.{ "docker", "run", "--rm", "--security-opt", "seccomp=unconfined" });
if (arch != builtin.cpu.arch) {
if (arch == .x86_64) {
docker_test_cmd.addArgs(&.{ "--platform", "linux/amd64" });
} else if (arch == .aarch64) {
docker_test_cmd.addArgs(&.{ "--platform", "linux/arm64" });
}
}
docker_test_cmd.addArgs(&.{ "-v", "./zig-out:/zig-out", "alpine" });
docker_test_cmd.addArg(b.fmt("/zig-out/bin/tests{s}", .{bin_suffix}));
docker_test_cmd.step.dependOn(test_install_step.?);
test_cli_step.dependOn(&docker_test_cmd.step);
// 'run-node' runs Node SDK test in a Docker container
const node_cli_step = b.step("run-node", "Run Node SDK test.ts in Docker container against the current build");
if (arch != builtin.cpu.arch) {
node_cli_step.dependOn(&b.addFail("zig build run-node requires native arch").step);
} else {
const image_tag = "bvisor-node-test";
const docker_build = b.addSystemCommand(&.{
"docker", "build", "-t", image_tag, "./src/sdks/node",
});
const script = b.option([]const u8, "script", "Script for run-node to execute (default: test.ts)") orelse "test.ts";
const interactive_arg = if (interactive) " --interactive" else "";
const log_level_arg = if (log_level == .debug) " --log-level DEBUG" else "";
const shell_cmd = b.fmt("bun install && bun {s}{s}{s}", .{
script,
interactive_arg,
log_level_arg,
});
var node_cmd_args: std.ArrayListUnmanaged([]const u8) = .empty;
node_cmd_args.appendSlice(b.allocator, &.{
"docker", "run", "--rm", "--security-opt", "seccomp=unconfined",
}) catch @panic("OOM");
if (interactive) {
node_cmd_args.appendSlice(b.allocator, &.{ "-i", "-t" }) catch @panic("OOM");
}
node_cmd_args.appendSlice(b.allocator, &.{
"-v", "./src/sdks/node:/app", "-w", "/app", image_tag,
"sh", "-c", shell_cmd,
}) catch @panic("OOM");
const node_cmd = b.addSystemCommand(node_cmd_args.items);
if (interactive) {
node_cmd.stdio = .inherit;
}
node_cmd.step.dependOn(&docker_build.step);
for (arch_node_installs[0..arch_node_count]) |step| node_cmd.step.dependOn(step);
node_cli_step.dependOn(&node_cmd.step);
}
}