1b: *std.Build,
2options: Options,
3root_step: *std.Build.Step,
4
5libc_test_src_path: std.Build.LazyPath,
6
7test_cases: std.ArrayList(TestCase) = .empty,
8
9pub const Options = struct {
10 optimize_modes: []const std.builtin.Optimize,
11 test_filters: []const []const u8,
12 test_target_filters: []const []const u8,
13 skip_wasm: bool,
14 max_rss: u64,
15};
16
17const TestCase = struct {
18 name: []const u8,
19 src_file: std.Build.LazyPath,
20 additional_src_file: ?std.Build.LazyPath,
21 supports_wasi_libc: bool,
22};
23
24pub const LibcTestCaseOption = struct {
25 additional_src_file: ?[]const u8 = null,
26};
27
28pub fn addLibcTestCase(
29 libc: *Libc,
30 path: []const u8,
31 supports_wasi_libc: bool,
32 options: LibcTestCaseOption,
33) void {
34 const graph = libc.b.graph;
35 const arena = graph.arena;
36 const name = arena.dupe(u8, path[0 .. path.len - std.fs.path.extension(path).len]) catch @panic("OOM");
37 std.mem.replaceScalar(u8, name, '/', '.');
38 libc.test_cases.append(arena, .{
39 .name = name,
40 .src_file = libc.libc_test_src_path.path(libc.b, path),
41 .additional_src_file = if (options.additional_src_file) |additional_src_file| libc.libc_test_src_path.path(libc.b, additional_src_file) else null,
42 .supports_wasi_libc = supports_wasi_libc,
43 }) catch @panic("OOM");
44}
45
46pub fn addTarget(libc: *const Libc, target: std.Build.ResolvedTarget) void {
47 if (libc.options.skip_wasm and target.query.cpu_arch != null and target.query.cpu_arch.?.isWasm()) return;
48
49 if (libc.options.test_target_filters.len > 0) {
50 const triple_txt = target.query.zigTriple(libc.b.allocator) catch @panic("OOM");
51 for (libc.options.test_target_filters) |filter| {
52 if (std.mem.find(u8, triple_txt, filter)) |_| break;
53 } else return;
54 }
55
56 const common = libc.libc_test_src_path.path(libc.b, "common");
57
58 for (libc.options.optimize_modes) |optimize| {
59 const libtest_mod = libc.b.createModule(.{
60 .target = target,
61 .optimize = optimize,
62 .link_libc = true,
63 });
64
65 var libtest_c_source_files: []const []const u8 = &.{
66 "print.c", "rand.c", "mtest.c", "setrlim.c", "memfill.c", "vmfill.c", "fdfill.c", "utf8.c",
67 };
68 libtest_mod.addCSourceFiles(.{
69 .root = common,
70 .files = libtest_c_source_files[0..if (target.result.isMuslLibC()) 8 else 3],
71 .flags = &.{"-fno-builtin"},
72 });
73
74 const libtest = libc.b.addLibrary(.{
75 .name = "test",
76 .root_module = libtest_mod,
77 });
78
79 for (libc.test_cases.items) |*test_case| {
80 if (target.result.isWasiLibC() and !test_case.supports_wasi_libc)
81 continue;
82
83 const annotated_case_name = libc.b.fmt("run libc-test {s} ({t})", .{ test_case.name, optimize });
84 for (libc.options.test_filters) |test_filter| {
85 if (std.mem.find(u8, annotated_case_name, test_filter)) |_| break;
86 } else if (libc.options.test_filters.len > 0) continue;
87
88 const mod = libc.b.createModule(.{
89 .target = target,
90 .optimize = optimize,
91 .link_libc = true,
92 });
93 mod.addIncludePath(common);
94 if (target.result.isWasiLibC())
95 mod.addCMacro("_WASI_EMULATED_SIGNAL", "");
96 mod.addCSourceFile(.{
97 .file = test_case.src_file,
98 .flags = &.{"-fno-builtin"},
99 });
100 if (test_case.additional_src_file) |additional_src_file| {
101 mod.addCSourceFile(.{
102 .file = additional_src_file,
103 .flags = &.{"-fno-builtin"},
104 });
105 }
106 mod.linkLibrary(libtest);
107
108 const exe = libc.b.addExecutable(.{
109 .name = test_case.name,
110 .root_module = mod,
111 .max_rss = libc.options.max_rss,
112 });
113
114 const run = libc.b.addRunArtifact(exe);
115 run.setName(annotated_case_name);
116 run.skip_foreign_checks = true;
117 run.disable_zig_progress = true; // can interfere with fd count assumptions
118 run.expectStdErrEqual("");
119 run.expectStdOutEqual("");
120 run.expectExitCode(0);
121 run.step.max_rss = libc.options.max_rss;
122
123 libc.root_step.dependOn(&run.step);
124 }
125 }
126}
127
128const Libc = @This();
129const std = @import("std");