const std = @import("std"); // the gils coreutils const gils_tools = .{ "gils", "ls", "tree", "cat", "rm", "mkdir", "touch", "cp", "mv", "wc", "head", "tail", "ed" }; pub fn build(b: *std.Build) void { // Default to ReleaseSafe because Debug pulls Zig's UBSan runtime and other // sanitization, which needs f128/SSE ops, which i don't provide. const optimize = b.option(std.builtin.OptimizeMode, "optimize", "optimize mode") orelse .safe; // The kernel must NOT touch SSE/MMX/AVX until it has enabled them itself, so // I strip those features and let the compiler use a soft-float ABI // `code_model = .kernel` keeps relocations valid for the higher-half load // address in boot/linker.ld. // // In other words. Going raw baby var query: std.Target.Query = .{ .cpu_arch = .x86_64, .os_tag = .freestanding, .abi = .none, }; const Feature = std.Target.x86.Feature; query.cpu_features_sub.addFeature(@backingInt(Feature.mmx)); query.cpu_features_sub.addFeature(@backingInt(Feature.avx)); query.cpu_features_sub.addFeature(@backingInt(Feature.avx2)); const target = b.resolveTargetQuery(query); const kernel = b.addExecutable(.{ .name = "revel", .root_module = b.createModule(.{ .root_source_file = b.path("boot/boot.zig"), .target = target, .optimize = optimize, .code_model = .kernel, .red_zone = false, .single_threaded = true, .link_libc = false, }), }); kernel.entry = .{ .symbol_name = "_start" }; kernel.pie = false; kernel.setLinkerScript(b.path("boot/linker.ld")); // the big guns const revo_dep = b.dependency("revo", .{ .target = target, .optimize = optimize, .features = "regex", }); const revo_mod = revo_dep.module("revo"); var visited: std.AutoHashMap(*std.Build.Module, void) = .init(b.allocator); defer visited.deinit(); kernelize(revo_mod, &visited); // the thin guns const bridge_mod = b.createModule(.{ .root_source_file = b.path("bridge/bridge.zig"), .target = target, .optimize = optimize, .code_model = .kernel, .red_zone = false, .single_threaded = true, .link_libc = false, }); bridge_mod.addImport("revo", revo_mod); inline for (.{ .{ "k_font", "kernel/font.rv" }, .{ "k_console", "kernel/console.rv" }, .{ "k_vmm", "kernel/vmm.rv" }, .{ "k_fs", "kernel/fs.rv" }, .{ "k_io", "kernel/io.rv" }, .{ "k_vfs", "kernel/vfs.rv" }, .{ "k_seed", "kernel/seed.rv" }, .{ "k_proc", "kernel/proc.rv" }, .{ "k_ttf", "kernel/ttf.rv" }, .{ "k_shell", "kernel/shell.rv" }, .{ "k_tty", "kernel/tty.rv" }, .{ "k_input", "kernel/input.rv" }, .{ "k_main", "kernel/main.rv" }, }) |e| { bridge_mod.addAnonymousImport(e[0], .{ .root_source_file = b.path(e[1]) }); } // load gils inline for (gils_tools) |g| { bridge_mod.addAnonymousImport("k_gils_" ++ g, .{ .root_source_file = b.path("gils/" ++ g ++ ".rv") }); } kernel.root_module.addImport("bridge", bridge_mod); inline for (.{ .{ "font_vga16", "fonts/vga16.psf" }, .{ "font_vga8", "fonts/vga8.psf" }, .{ "font_sun16", "fonts/sun16.psf" }, .{ "font_acorn8", "fonts/acorn8.psf" }, .{ "font_pearl8", "fonts/pearl8.psf" }, .{ "font_dejavu", "fonts/dejavu.ttf" }, .{ "font_terminess", "fonts/terminess.ttf" }, }) |e| { kernel.root_module.addAnonymousImport(e[0], .{ .root_source_file = b.path(e[1]) }); } inline for (.{ "hexview", "calc", "primes", "save", "chat" }) |prog| { const cc = b.addSystemCommand(&.{ "zig", "cc", "-target", "x86_64-freestanding", "-ffreestanding", "-nostdlib", "-static", "-no-pie", "-fno-stack-protector", "-fno-sanitize=all", "-Wl,-T,user/link.ld", "-Wl,--build-id=none", "-o", }); const prog_elf = cc.addOutputFileArg(prog ++ ".elf"); cc.addFileArg(b.path("user/" ++ prog ++ ".c")); cc.addFileInput(b.path("user/user.h")); cc.addFileInput(b.path("user/link.ld")); kernel.root_module.addAnonymousImport("user_" ++ prog, .{ .root_source_file = prog_elf }); } b.installArtifact(kernel); } // force a module and everything it imports to the kernel's codegen settings fn kernelize(mod: *std.Build.Module, visited: *std.AutoHashMap(*std.Build.Module, void)) void { if (visited.contains(mod)) return; visited.put(mod, {}) catch @panic("OOM building module graph"); mod.code_model = .kernel; mod.red_zone = false; mod.single_threaded = true; var it = mod.import_table.iterator(); while (it.next()) |entry| kernelize(entry.value_ptr.*, visited); }