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 }