const std = @import("std"); const Arch = enum { x86_64, aarch64, pub fn target(self: Arch) std.Target.Cpu.Arch { return switch (self) { .x86_64 => .x86_64, .aarch64 => .aarch64, }; } pub const EfiName = enum { X64, AA64 }; pub fn efi(self: Arch) EfiName { return switch (self) { .x86_64 => .X64, .aarch64 => .AA64, }; } }; fn lumineExecutable(b: *std.Build, cpu_arch: Arch, optimize: std.builtin.OptimizeMode) *std.Build.Step.Compile { const target = b.resolveTargetQuery(.{ .cpu_arch = cpu_arch.target(), .cpu_model = .baseline, .os_tag = .uefi, }); return b.addExecutable(.{ .name = b.fmt("BOOT{t}", .{cpu_arch.efi()}), .root_module = b.createModule(.{ .target = target, .optimize = optimize, .root_source_file = b.path("src/main.zig"), }), }); } pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const cpu_arch = b.option(Arch, "arch", "cpu architecture") orelse .x86_64; const install_step = b.getInstallStep(); const lumine_exe = lumineExecutable(b, cpu_arch, optimize); const lumine_install = b.addInstallArtifact(lumine_exe, .{}); install_step.dependOn(&lumine_install.step); const all_step = b.step("all", "build for all supported architectures"); inline for (@typeInfo(Arch).@"enum".fields) |field| { const arch_exe = lumineExecutable(b, @field(Arch, field.name), optimize); const arch_install = b.addInstallArtifact(arch_exe, .{}); all_step.dependOn(&arch_install.step); } const qemu_exe = b.option([]const u8, "qemu", "ovveride qemu executable") orelse b.fmt("qemu-system-{t}", .{cpu_arch}); const qemu_cmd = b.addSystemCommand(&.{ qemu_exe, "-m", "512M", "-no-reboot", "-no-shutdown" }); const no_serial = b.option(bool, "no-serial", "dont add stdio serial commands") orelse false; if (!no_serial) { qemu_cmd.addArgs(&.{ "-serial", "mon:stdio", "-nographic" }); } switch (cpu_arch) { .aarch64 => qemu_cmd.addArgs(&.{ "-M", "virt", "-cpu", "cortex-a57" }), .x86_64 => {}, } const ovmf_override = b.option(std.Build.LazyPath, "ovmf", "override ovmf firmware dependency"); const ovmf_use_dep = b.option(bool, "ovmf-dep", "use ovmf dependency instead") orelse false; if (ovmf_use_dep) { if (b.lazyDependency("ovmf", .{})) |ovmf_dep| { const ovmf_code = ovmf_dep.path(b.fmt("ovmf-code-{t}.fd", .{cpu_arch})); qemu_cmd.addArg("-bios"); qemu_cmd.addFileArg(ovmf_code); } } else if (ovmf_override) |override| { qemu_cmd.addArg("-bios"); qemu_cmd.addFileArg(override); } else { const fail = b.addFail("ovmf not specified, either use -Dovmf=PATH_TO_OVMF_CODE_BIN or use -Dovmf-dep to download as dependency"); qemu_cmd.step.dependOn(&fail.step); } { // https://codeberg.org/ziglang/zig/issues/32041 // https://codeberg.org/dragsbruh/minimux/releases const linux_dir = b.option([]const u8, "linux", "dir containing `vmlinuz` and `initrd.xz`") orelse b.fmt("res/{t}", .{cpu_arch}); const config_file = b.option([]const u8, "config", "path to config file") orelse "res/lumine.zon"; const boot_dir = b.addTempFiles(); _ = boot_dir.addCopyFile(b.path(config_file), "lumine.zon"); _ = boot_dir.addCopyFile(lumine_exe.getEmittedBin(), b.fmt("EFI/BOOT/BOOT{t}.EFI", .{cpu_arch.efi()})); _ = boot_dir.addCopyFile(b.path(linux_dir).path(b, "vmlinuz"), "linux/vmlinuz"); _ = boot_dir.addCopyFile(b.path(linux_dir).path(b, "initrd.xz"), "linux/initrd.xz"); qemu_cmd.addArg("-drive"); qemu_cmd.addPrefixedDirectoryArg("format=raw,file=fat:rw:", boot_dir.getDirectory()); } const run_step = b.step("run", "run in qemu"); run_step.dependOn(&qemu_cmd.step); }