stage0-specific changes

This commit is contained in:
2026-02-13 23:47:23 +02:00
parent b81f72bab3
commit 7c8248c241
9 changed files with 972 additions and 49 deletions

208
build.zig
View File

@@ -10,6 +10,29 @@ const assert = std.debug.assert;
const DevEnv = @import("src/dev.zig").Env;
const ValueInterpretMode = enum { direct, by_name };
const zig0_headers = &[_][]const u8{ "common.h", "ast.h", "parser.h", "zir.h", "astgen.h" };
const zig0_c_lib_files = &[_][]const u8{ "tokenizer.c", "ast.c", "zig0.c", "parser.c", "zir.c", "astgen.c" };
const zig0_all_c_files = zig0_c_lib_files ++ &[_][]const u8{"main.c"};
const zig0_cflags = &[_][]const u8{
"-std=c11",
"-Wall",
"-Wvla",
"-Wextra",
"-Werror",
"-Wshadow",
"-Wswitch",
"-Walloca",
"-Wformat=2",
"-fno-common",
"-Wconversion",
"-Wuninitialized",
"-Wdouble-promotion",
"-fstack-protector-all",
"-Wimplicit-fallthrough",
"-Wno-unused-function",
};
const zig0_compilers = &[_][]const u8{ "zig", "clang", "gcc", "tcc" };
const zig_version: std.SemanticVersion = .{ .major = 0, .minor = 15, .patch = 1 };
const stack_size = 46 * 1024 * 1024;
@@ -273,15 +296,15 @@ pub fn build(b: *std.Build) !void {
2 => {
// Untagged development build (e.g. 0.10.0-dev.2025+ecf0050a9).
var it = mem.splitScalar(u8, git_describe, '-');
const tagged_ancestor = it.first();
//const tagged_ancestor = it.first();
const commit_height = it.next().?;
const commit_id = it.next().?;
const ancestor_ver = try std.SemanticVersion.parse(tagged_ancestor);
if (zig_version.order(ancestor_ver) != .gt) {
std.debug.print("Zig version '{f}' must be greater than tagged ancestor '{f}'\n", .{ zig_version, ancestor_ver });
std.process.exit(1);
}
//const ancestor_ver = try std.SemanticVersion.parse(tagged_ancestor);
//if (zig_version.order(ancestor_ver) != .gt) {
// std.debug.print("Zig version '{f}' must be greater than tagged ancestor '{f}'\n", .{ zig_version, ancestor_ver });
// std.process.exit(1);
//}
// Check that the commit hash is prefixed with a 'g' (a Git convention).
if (commit_id.len < 1 or commit_id[0] != 'g') {
@@ -630,6 +653,79 @@ pub fn build(b: *std.Build) !void {
const test_incremental_step = b.step("test-incremental", "Run the incremental compilation test cases");
try tests.addIncrementalTests(b, test_incremental_step);
test_step.dependOn(test_incremental_step);
// zig0 (C implementation) build steps
const zig0_cc = b.option([]const u8, "zig0-cc", "C compiler for zig0 tests") orelse "zig";
const zig0_no_exec = b.option(bool, "zig0-no-exec", "Compile zig0 test binary without running it") orelse false;
const zig0_test_timeout = b.option([]const u8, "zig0-test-timeout", "Test execution timeout for zig0 (default: 10s, none with valgrind)");
const zig0_valgrind = valgrind orelse false;
const zig0_target = blk: {
if (!zig0_valgrind) break :blk target;
var query = target.query;
//const arch = query.cpu_arch orelse @import("builtin").cpu.arch;
//if (arch == .x86_64) {
query.cpu_features_sub.addFeature(@intFromEnum(std.Target.x86.Feature.avx512f));
//}
break :blk b.resolveTargetQuery(query);
};
const test_zig0_step = b.step("test-zig0", "Run zig0 C implementation tests");
addZig0TestStep(b, test_zig0_step, zig0_target, optimize, zig0_cc, zig0_no_exec, zig0_valgrind, zig0_test_timeout);
const fmt_zig0 = b.step("fmt-zig0", "Format zig0 C code");
const clang_format = b.addSystemCommand(&.{ "clang-format", "-i" });
for (zig0_all_c_files ++ zig0_headers) |f| clang_format.addFileArg(b.path(b.fmt("stage0/{s}", .{f})));
fmt_zig0.dependOn(&clang_format.step);
const lint_zig0 = b.step("lint-zig0", "Run zig0 linters");
for (zig0_all_c_files) |cfile| {
const clang_analyze = b.addSystemCommand(&.{
"clang",
"--analyze",
"--analyzer-output",
"text",
"-Wno-unused-command-line-argument",
"-Werror",
"-Xclang",
"-analyzer-disable-checker",
"-Xclang",
"unix.Malloc",
});
clang_analyze.addFileArg(b.path(b.fmt("stage0/{s}", .{cfile})));
clang_analyze.step.name = b.fmt("clang --analyze ({s})", .{cfile});
clang_analyze.expectExitCode(0);
lint_zig0.dependOn(&clang_analyze.step);
const cppcheck = b.addSystemCommand(&.{
"cppcheck",
"--quiet",
"--error-exitcode=1",
"--check-level=exhaustive",
"--enable=all",
"--inline-suppr",
"--suppress=missingIncludeSystem",
"--suppress=checkersReport",
"--suppress=unusedFunction",
"--suppress=unusedStructMember",
"--suppress=unmatchedSuppression",
});
cppcheck.addFileArg(b.path(b.fmt("stage0/{s}", .{cfile})));
cppcheck.step.name = b.fmt("cppcheck ({s})", .{cfile});
cppcheck.expectExitCode(0);
lint_zig0.dependOn(&cppcheck.step);
}
const all_zig0 = b.step("all-zig0", "Run zig0 fmt check, lint, and tests with all compilers");
// fmt check (dry-run)
const zig0_fmt_check = b.addSystemCommand(&.{ "clang-format", "--dry-run", "-Werror" });
for (zig0_all_c_files ++ zig0_headers) |f| zig0_fmt_check.addFileArg(b.path(b.fmt("stage0/{s}", .{f})));
zig0_fmt_check.expectExitCode(0);
all_zig0.dependOn(&zig0_fmt_check.step);
all_zig0.dependOn(lint_zig0);
for (zig0_compilers) |compiler| {
addZig0TestStep(b, all_zig0, zig0_target, optimize, compiler, false, zig0_valgrind, zig0_test_timeout);
}
}
fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
@@ -1484,3 +1580,103 @@ fn superHtmlCheck(b: *std.Build, html_file: std.Build.LazyPath) *std.Build.Step
run_superhtml.expectExitCode(0);
return &run_superhtml.step;
}
fn addZig0TestStep(
b: *std.Build,
step: *std.Build.Step,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
cc: []const u8,
no_exec: bool,
valgrind: bool,
test_timeout: ?[]const u8,
) void {
const bridge_mod = b.createModule(.{
.root_source_file = b.path("stage0/zig0_bridge.zig"),
.target = target,
.optimize = optimize,
});
bridge_mod.addIncludePath(b.path("stage0"));
// Parser + tokenizer tests (hooks into std's test files via zig0 bridge)
const test_mod = b.createModule(.{
.root_source_file = b.path("lib/std/zig/zig0_test.zig"),
.optimize = optimize,
.target = target,
});
test_mod.addIncludePath(b.path("stage0"));
test_mod.addImport("zig0_bridge", bridge_mod);
// AstGen tests (standalone C-vs-Zig ZIR comparison)
const astgen_test_mod = b.createModule(.{
.root_source_file = b.path("stage0/astgen_test.zig"),
.optimize = optimize,
.target = target,
});
astgen_test_mod.addIncludePath(b.path("stage0"));
const timeout: ?[]const u8 = test_timeout orelse if (valgrind) null else "10";
for ([_]struct { mod: *std.Build.Module, name: []const u8 }{
.{ .mod = test_mod, .name = "test" },
.{ .mod = astgen_test_mod, .name = "astgen_test" },
}) |entry| {
addZig0CSources(b, entry.mod, cc, optimize);
entry.mod.linkSystemLibrary("c", .{});
const test_exe = b.addTest(.{
.root_module = entry.mod,
.use_llvm = false,
.use_lld = false,
});
if (valgrind) {
test_exe.setExecCmd(&.{
"valgrind",
"--error-exitcode=2",
"--leak-check=full",
"--show-leak-kinds=all",
"--errors-for-leak-kinds=all",
"--track-fds=yes",
"--quiet",
null,
});
} else {
test_exe.setExecCmd(&.{ "timeout", timeout orelse "10", null });
}
if (no_exec) {
const install = b.addInstallArtifact(test_exe, .{});
step.dependOn(&install.step);
} else {
const run = b.addRunArtifact(test_exe);
run.step.name = b.fmt("{s} ({s})", .{ entry.name, cc });
step.dependOn(&run.step);
}
}
}
fn addZig0CSources(
b: *std.Build,
mod: *std.Build.Module,
cc: []const u8,
optimize: std.builtin.OptimizeMode,
) void {
if (std.mem.eql(u8, cc, "zig")) {
mod.addCSourceFiles(.{
.root = b.path("stage0"),
.files = zig0_c_lib_files,
.flags = zig0_cflags,
});
} else for (zig0_c_lib_files) |cfile| {
const cc1 = b.addSystemCommand(&.{cc});
cc1.addArgs(zig0_cflags ++ .{"-g"});
cc1.addArg(switch (optimize) {
.Debug => "-O0",
.ReleaseFast, .ReleaseSafe => "-O3",
.ReleaseSmall => "-Os",
});
cc1.addArg("-c");
cc1.addFileArg(b.path(b.fmt("stage0/{s}", .{cfile})));
cc1.addArg("-o");
mod.addObjectFile(cc1.addOutputFileArg(b.fmt("{s}.o", .{cfile[0 .. cfile.len - 2]})));
}
}