sylveos

Toy Operating System
Log | Files | Refs

build.zig (6811B)


      1 const std = @import("std");
      2 const builtin = @import("builtin");
      3 
      4 fn pi_zero_target(b: *std.Build) std.Build.ResolvedTarget {
      5     var cpu_features = std.Target.arm.cpu.arm1176jzf_s.features;
      6     cpu_features.addFeatureSet(std.Target.arm.featureSet(&[_]std.Target.arm.Feature{.strict_align}));
      7     cpu_features.removeFeatureSet(std.Target.arm.featureSet(&[_]std.Target.arm.Feature{.vfp2}));
      8 
      9     const query: std.Target.Query = .{
     10         .cpu_arch = .arm,
     11         .cpu_model = .{ .explicit = &std.Target.arm.cpu.arm1176jzf_s },
     12         .cpu_features_add = cpu_features,
     13         .os_tag = .freestanding,
     14         .abi = .eabi,
     15     };
     16 
     17     return b.resolveTargetQuery(query);
     18 }
     19 
     20 fn pi_module_opts(target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, path: ?std.Build.LazyPath) std.Build.Module.CreateOptions {
     21     return .{
     22         .root_source_file = path,
     23         .target = target,
     24         .optimize = optimize,
     25         .link_libc = false,
     26         .omit_frame_pointer = true,
     27         .single_threaded = true,
     28         .no_builtin = true,
     29         .pic = true,
     30     };
     31 }
     32 
     33 const BinaryMode = enum {
     34     Bootloader,
     35     Standalone,
     36     Bootable,
     37 };
     38 
     39 fn build_pi(
     40     b: *std.Build,
     41     target: std.Build.ResolvedTarget,
     42     optimize: std.builtin.OptimizeMode,
     43     name: []const u8,
     44     program_path: std.Build.LazyPath,
     45     default_mode: ?BinaryMode,
     46 ) !*std.Build.Module {
     47     const mode = default_mode orelse b.option(BinaryMode, "mode", "specify binary output mode") orelse .Bootable;
     48 
     49     const shared = b.createModule(pi_module_opts(target, optimize, b.path("shared/root.zig")));
     50 
     51     const pi = b.createModule(pi_module_opts(target, optimize, b.path("pi/root.zig")));
     52     pi.addImport("shared", shared);
     53     pi.addIncludePath(b.path("include/"));
     54     pi.addCSourceFile(.{ .file = b.path("include/emmc.c") });
     55     pi.addCSourceFile(.{ .file = b.path("include/pi-sd.c") });
     56 
     57     const program = b.createModule(pi_module_opts(target, optimize, program_path));
     58     program.addImport("shared", shared);
     59     program.addImport("pi", pi);
     60 
     61     // TODO; boot/root.zig could probably just read some config flag we pass down
     62     const boot_stub_path = switch (mode) {
     63         .Bootable => b.path("boot/bootable.zig"),
     64         .Bootloader => b.path("boot/bootloader.zig"),
     65         .Standalone => b.path("boot/standalone.zig"),
     66     };
     67     const boot_stub = b.createModule(pi_module_opts(target, optimize, boot_stub_path));
     68     boot_stub.addImport("shared", shared);
     69 
     70     const root = b.createModule(pi_module_opts(target, optimize, b.path("boot/root.zig")));
     71     root.addImport("shared", shared);
     72     root.addImport("boot", boot_stub);
     73     root.addImport("pi", pi);
     74 
     75     root.addImport("program", program);
     76 
     77     const exe_name = try std.fmt.allocPrint(b.allocator, "{s}.elf", .{name});
     78     defer b.allocator.free(exe_name);
     79 
     80     const exe = b.addExecutable(.{
     81         .name = exe_name,
     82         .linkage = .static,
     83         .root_module = root,
     84         .use_lld = true,
     85         .use_llvm = true,
     86     });
     87     exe.link_function_sections = true;
     88     exe.link_data_sections = true;
     89     exe.link_gc_sections = true;
     90     exe.lto = .full;
     91 
     92     exe.setLinkerScript(b.path("pi/linker.ld"));
     93     b.installArtifact(exe);
     94 
     95     const obj_copy = b.addObjCopy(exe.getEmittedBin(), .{
     96         .format = .bin,
     97     });
     98     obj_copy.step.dependOn(&exe.step);
     99 
    100     const bin_name = try std.fmt.allocPrint(b.allocator, "{s}.bin", .{name});
    101     defer b.allocator.free(bin_name);
    102 
    103     const install_bin = b.addInstallBinFile(obj_copy.getOutput(), bin_name);
    104     b.getInstallStep().dependOn(&install_bin.step);
    105 
    106     return program;
    107 }
    108 
    109 fn build_sylveos_vm(
    110     b: *std.Build,
    111     target: std.Build.ResolvedTarget,
    112     optimize: std.builtin.OptimizeMode,
    113 ) !*std.Build.Step.ObjCopy {
    114     const shared = b.createModule(pi_module_opts(target, optimize, b.path("shared/root.zig")));
    115     const pi = b.createModule(pi_module_opts(target, optimize, b.path("pi/root.zig")));
    116     pi.addImport("shared", shared);
    117     pi.addIncludePath(b.path("include/"));
    118     pi.addCSourceFile(.{ .file = b.path("include/emmc.c") });
    119     pi.addCSourceFile(.{ .file = b.path("include/pi-sd.c") });
    120 
    121     const root = b.createModule(pi_module_opts(target, optimize, b.path("sylveos/root.zig")));
    122     root.addImport("shared", shared);
    123     root.addImport("pi", pi);
    124 
    125     const exe = b.addExecutable(.{
    126         .name = "sylveos.elf",
    127         .linkage = .static,
    128         .root_module = root,
    129         .use_lld = true,
    130         .use_llvm = true,
    131     });
    132     exe.link_function_sections = true;
    133     exe.link_data_sections = true;
    134     exe.link_gc_sections = true;
    135     exe.lto = .full;
    136 
    137     exe.setLinkerScript(b.path("sylveos/linker.ld"));
    138     b.installArtifact(exe);
    139 
    140     const obj_copy = b.addObjCopy(exe.getEmittedBin(), .{
    141         .format = .bin,
    142     });
    143     obj_copy.step.dependOn(&exe.step);
    144 
    145     const install_bin = b.addInstallBinFile(obj_copy.getOutput(), "sylveos.bin");
    146     b.getInstallStep().dependOn(&install_bin.step);
    147 
    148     return obj_copy;
    149 }
    150 
    151 fn build_program(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, program: []const u8, mode: ?BinaryMode) !void {
    152     const program_name = try std.fmt.allocPrint(b.allocator, "programs/{s}.zig", .{program});
    153     defer b.allocator.free(program_name);
    154 
    155     _ = try build_pi(b, target, optimize, program, b.path(program_name), mode);
    156 }
    157 
    158 fn build_all_programs(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) !void {
    159     const path = try b.path("programs").getPath3(b, null).toString(b.allocator);
    160     defer b.allocator.free(path);
    161 
    162     var dir = try std.fs.openDirAbsolute(path, .{ .access_sub_paths = false, .iterate = true });
    163     defer dir.close();
    164 
    165     var iter = dir.iterate();
    166     while (try iter.next()) |entry| {
    167         if (entry.kind != .file) continue;
    168         if (!std.mem.endsWith(u8, entry.name, ".zig")) continue;
    169         const name = entry.name[0..(entry.name.len - 4)];
    170 
    171         try build_program(b, target, optimize, name, .Bootable);
    172     }
    173 }
    174 
    175 pub fn build(b: *std.Build) !void {
    176     const pi_target = pi_zero_target(b);
    177     const optimize = b.standardOptimizeOption(.{ .preferred_optimize_mode = .ReleaseSafe });
    178 
    179     const program = b.option([]const u8, "program", "specify pi program") orelse {
    180         try build_all_programs(b, pi_target, optimize);
    181         _ = try build_pi(b, pi_target, optimize, "sylveos", b.path("sylveos/root.zig"), .Bootable);
    182 
    183         return;
    184     };
    185 
    186     if (std.mem.eql(u8, program, "sylveos-boot")) {
    187         _ = try build_pi(b, pi_target, optimize, "sylveos-boot", b.path("sylveos/boot.zig"), null);
    188     } else if (std.mem.eql(u8, program, "sylveos")) {
    189         _ = try build_sylveos_vm(b, pi_target, optimize);
    190     } else {
    191         try build_program(b, pi_target, optimize, program, null);
    192     }
    193 }