| ... | ... | @@ -2,6 +2,7 @@ const ObjCopy = @This(); |
| 2 | 2 | |
| 3 | 3 | const std = @import("std"); |
| 4 | 4 | const Io = std.Io; |
| 5 | const Path = std.Build.Cache.Path; |
| 5 | 6 | const allocPrint = std.fmt.allocPrint; |
| 6 | 7 | const Configuration = std.Build.Configuration; |
| 7 | 8 | |
| ... | ... | @@ -23,120 +24,152 @@ pub fn make( |
| 23 | 24 | const conf_step = step_index.ptr(conf); |
| 24 | 25 | const conf_oc = conf_step.extended.get(conf.extra).obj_copy; |
| 25 | 26 | const cache_root = graph.local_cache_root; |
| 27 | const input_lazy_path = conf_oc.input_file.get(conf); |
| 28 | const only_section: ?[]const u8 = if (conf_oc.only_section.value) |s| s.slice(conf) else null; |
| 29 | const opt_basename: ?[]const u8 = if (conf_oc.basename.value) |s| s.slice(conf) else null; |
| 30 | const opt_debug_basename: ?[]const u8 = if (conf_oc.debug_basename.value) |s| s.slice(conf) else null; |
| 26 | 31 | |
| 27 | | try step.singleUnchangingWatchInput(maker, arena, conf_oc.input_file); |
| 32 | try step.singleUnchangingWatchInput(maker, arena, input_lazy_path); |
| 28 | 33 | |
| 29 | 34 | var man = graph.cache.obtain(); |
| 30 | 35 | defer man.deinit(); |
| 31 | 36 | |
| 32 | | const src_path = try maker.resolveLazyPathIndex(arena, conf_oc.input_file, step_index); |
| 33 | | _ = try man.addFilePath(src_path, null); |
| 34 | | man.hash.addOptionalBytes(conf_oc.only_section); |
| 35 | | man.hash.addOptional(conf_oc.pad_to); |
| 36 | | man.hash.addOptional(conf_oc.format); |
| 37 | | man.hash.add(conf_oc.compress_debug); |
| 38 | | man.hash.add(conf_oc.strip); |
| 39 | | man.hash.add(conf_oc.output_file_debug != null); |
| 37 | const input_path = try maker.resolveLazyPath(arena, input_lazy_path, step_index); |
| 38 | _ = try man.addFilePath(input_path, null); |
| 39 | man.hash.addOptionalBytes(only_section); |
| 40 | man.hash.addOptionalBytes(opt_basename); |
| 41 | man.hash.addOptionalBytes(opt_debug_basename); |
| 42 | man.hash.addOptional(conf_oc.pad_to.value); |
| 43 | man.hash.add(conf_oc.flags.format); |
| 44 | man.hash.add(conf_oc.flags.compress_debug); |
| 45 | man.hash.add(conf_oc.flags.strip); |
| 46 | man.hash.add(conf_oc.debug_file.value != null); |
| 40 | 47 | |
| 41 | | if (try step.cacheHit(&man)) { |
| 48 | const basename = opt_basename orelse Io.Dir.path.basename(input_path.sub_path); |
| 49 | |
| 50 | if (try step.cacheHit(maker, &man)) { |
| 42 | 51 | // Cache hit, skip subprocess execution. |
| 43 | 52 | const digest = man.final(); |
| 44 | | conf_oc.output_file.path = try cache_root.join(arena, &.{ |
| 45 | | "o", &digest, conf_oc.basename, |
| 46 | | }); |
| 47 | | if (conf_oc.output_file_debug) |*file| { |
| 48 | | file.path = try cache_root.join(arena, &.{ |
| 49 | | "o", &digest, try allocPrint(arena, "{s}.debug", .{conf_oc.basename}), |
| 53 | maker.generatedPath(conf_oc.output_file).* = .{ |
| 54 | .root_dir = cache_root, |
| 55 | .sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest, basename }), |
| 56 | }; |
| 57 | if (conf_oc.debug_file.value) |debug_file| { |
| 58 | const debug_basename = opt_debug_basename orelse try allocPrint(arena, "{s}.debug", .{ |
| 59 | Io.Dir.path.basename(input_path.sub_path), |
| 50 | 60 | }); |
| 61 | maker.generatedPath(debug_file).* = .{ |
| 62 | .root_dir = cache_root, |
| 63 | .sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest, debug_basename }), |
| 64 | }; |
| 51 | 65 | } |
| 52 | 66 | return; |
| 53 | 67 | } |
| 54 | 68 | |
| 69 | // We don't find out more input files while executing objcopy so we can |
| 70 | // already obtain the digest and use it directly as the output path. |
| 55 | 71 | const digest = man.final(); |
| 56 | | const cache_path = "o" ++ Io.Dir.path.sep_str ++ digest; |
| 57 | | const full_dest_path = try cache_root.join(arena, &.{ cache_path, conf_oc.basename }); |
| 58 | | const full_dest_path_debug = try cache_root.join(arena, &.{ |
| 59 | | cache_path, try allocPrint(arena, "{s}.debug", .{conf_oc.basename}), |
| 60 | | }); |
| 61 | | cache_root.handle.createDirPath(io, cache_path) catch |err| |
| 62 | | return step.fail("unable to make path {s}: {t}", .{ cache_path, err }); |
| 72 | const dest_path: Path = .{ |
| 73 | .root_dir = cache_root, |
| 74 | .sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest, basename }), |
| 75 | }; |
| 76 | const dest_dirname = dest_path.dirname().?; |
| 77 | dest_dirname.root_dir.handle.createDirPath(io, dest_dirname.sub_path) catch |err| |
| 78 | return step.fail(maker, "failed to create path {f}: {t}", .{ dest_dirname, err }); |
| 63 | 79 | |
| 64 | 80 | var argv: std.ArrayList([]const u8) = .empty; |
| 65 | 81 | try argv.ensureUnusedCapacity(arena, 11); |
| 66 | 82 | |
| 67 | 83 | argv.addManyAsArrayAssumeCapacity(2).* = .{ graph.zig_exe, "objcopy" }; |
| 68 | 84 | |
| 69 | | if (conf_oc.only_section) |only_section| |
| 70 | | argv.addManyAsArrayAssumeCapacity(2).* = .{ "-j", only_section }; |
| 85 | if (only_section) |s| argv.addManyAsArrayAssumeCapacity(2).* = .{ "-j", s }; |
| 71 | 86 | |
| 72 | | switch (conf_oc.strip) { |
| 87 | switch (conf_oc.flags.strip) { |
| 73 | 88 | .none => {}, |
| 74 | 89 | .debug => argv.appendAssumeCapacity("--strip-debug"), |
| 75 | 90 | .debug_and_symbols => argv.appendAssumeCapacity("--strip-all"), |
| 76 | 91 | } |
| 77 | 92 | |
| 78 | | if (conf_oc.pad_to) |pad_to| { |
| 93 | if (conf_oc.pad_to.value) |pad_to| { |
| 79 | 94 | argv.addManyAsArrayAssumeCapacity(2).* = .{ |
| 80 | 95 | "--pad-to", try allocPrint(arena, "{d}", .{pad_to}), |
| 81 | 96 | }; |
| 82 | 97 | } |
| 83 | 98 | |
| 84 | | if (conf_oc.format) |format| { |
| 85 | | argv.addManyAsArrayAssumeCapacity(2).* = .{ |
| 86 | | "-O", |
| 87 | | switch (format) { |
| 88 | | .bin => "binary", |
| 89 | | .hex => "hex", |
| 90 | | .elf => "elf", |
| 91 | | }, |
| 92 | | }; |
| 99 | switch (conf_oc.flags.format) { |
| 100 | .default => {}, |
| 101 | else => |t| argv.addManyAsArrayAssumeCapacity(2).* = .{ "-O", @tagName(t) }, |
| 93 | 102 | } |
| 94 | 103 | |
| 95 | | if (conf_oc.compress_debug) |
| 104 | if (conf_oc.flags.compress_debug) |
| 96 | 105 | argv.appendAssumeCapacity("--compress-debug-sections"); |
| 97 | 106 | |
| 98 | | if (conf_oc.output_file_debug != null) |
| 99 | | argv.appendAssumeCapacity(try allocPrint(arena, "--extract-to={s}", .{full_dest_path_debug})); |
| 107 | if (conf_oc.debug_file.value) |debug_file| { |
| 108 | const debug_basename = opt_debug_basename orelse try allocPrint(arena, "{s}.debug", .{ |
| 109 | Io.Dir.path.basename(input_path.sub_path), |
| 110 | }); |
| 111 | const debug_dest_path: Path = .{ |
| 112 | .root_dir = cache_root, |
| 113 | .sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest, debug_basename }), |
| 114 | }; |
| 115 | argv.appendAssumeCapacity(try allocPrint(arena, "--extract-to={f}", .{debug_dest_path})); |
| 116 | maker.generatedPath(debug_file).* = debug_dest_path; |
| 117 | } |
| 100 | 118 | |
| 101 | | try argv.ensureUnusedCapacity(arena, 9); |
| 119 | try argv.ensureUnusedCapacity(arena, conf_oc.add_section.slice.len * 2); |
| 102 | 120 | |
| 103 | | if (conf_oc.add_section) |section| { |
| 121 | for (conf_oc.add_section.slice) |section| { |
| 104 | 122 | argv.appendAssumeCapacity("--add-section"); |
| 105 | 123 | argv.appendAssumeCapacity(try allocPrint(arena, "{s}={f}", .{ |
| 106 | | section.section_name, try maker.resolveLazyPathIndex(arena, section.file_path, step_index), |
| 124 | section.section_name.slice(conf), |
| 125 | try maker.resolveLazyPathIndex(arena, section.file_path, step_index), |
| 107 | 126 | })); |
| 108 | 127 | } |
| 109 | 128 | |
| 110 | | if (conf_oc.set_section_alignment) |set_align| { |
| 111 | | argv.appendAssumeCapacity("--set-section-alignment"); |
| 112 | | argv.appendAssumeCapacity(try allocPrint(arena, "{s}={d}", .{ set_align.section_name, set_align.alignment })); |
| 113 | | } |
| 129 | for (conf_oc.update_section.slice) |update| { |
| 130 | const name = update.section_name.slice(conf); |
| 114 | 131 | |
| 115 | | if (conf_oc.set_section_flags) |set_flags| { |
| 116 | | const f = set_flags.flags; |
| 117 | | // trailing comma is allowed |
| 118 | | argv.appendAssumeCapacity("--set-section-flags"); |
| 119 | | argv.appendAssumeCapacity(try allocPrint(arena, "{s}={s}{s}{s}{s}{s}{s}{s}{s}{s}", .{ |
| 120 | | set_flags.section_name, |
| 121 | | if (f.alloc) "alloc," else "", |
| 122 | | if (f.contents) "contents," else "", |
| 123 | | if (f.load) "load," else "", |
| 124 | | if (f.readonly) "readonly," else "", |
| 125 | | if (f.code) "code," else "", |
| 126 | | if (f.exclude) "exclude," else "", |
| 127 | | if (f.large) "large," else "", |
| 128 | | if (f.merge) "merge," else "", |
| 129 | | if (f.strings) "strings," else "", |
| 130 | | })); |
| 132 | try argv.ensureUnusedCapacity(arena, 4); |
| 133 | |
| 134 | if (update.flags.alignment.toBytes()) |a| { |
| 135 | argv.appendAssumeCapacity("--set-section-alignment"); |
| 136 | argv.appendAssumeCapacity(try allocPrint(arena, "{s}={d}", .{ name, a })); |
| 137 | } |
| 138 | |
| 139 | const f = update.flags.section_flags; |
| 140 | const default_flags: Configuration.Step.ObjCopy.SectionFlags = .{}; |
| 141 | |
| 142 | if (f != default_flags) { |
| 143 | // trailing comma is allowed |
| 144 | argv.appendAssumeCapacity("--set-section-flags"); |
| 145 | argv.appendAssumeCapacity(try allocPrint(arena, "{s}={s}{s}{s}{s}{s}{s}{s}{s}{s}", .{ |
| 146 | name, |
| 147 | if (f.alloc) "alloc," else "", |
| 148 | if (f.contents) "contents," else "", |
| 149 | if (f.load) "load," else "", |
| 150 | if (f.readonly) "readonly," else "", |
| 151 | if (f.code) "code," else "", |
| 152 | if (f.exclude) "exclude," else "", |
| 153 | if (f.large) "large," else "", |
| 154 | if (f.merge) "merge," else "", |
| 155 | if (f.strings) "strings," else "", |
| 156 | })); |
| 157 | } |
| 131 | 158 | } |
| 132 | 159 | |
| 133 | | argv.appendAssumeCapacity(src_path); |
| 134 | | argv.appendAssumeCapacity(full_dest_path); |
| 160 | argv.appendAssumeCapacity(try allocPrint(arena, "{f}", .{input_path})); |
| 161 | argv.appendAssumeCapacity(try allocPrint(arena, "{f}", .{dest_path})); |
| 135 | 162 | |
| 136 | 163 | argv.appendAssumeCapacity("--listen=-"); |
| 137 | | _ = try Step.evalZigProcess(step_index, maker, argv.items, progress_node, false); |
| 164 | _ = Step.evalZigProcess(step_index, maker, argv.items, progress_node, false) catch |err| switch (err) { |
| 165 | error.NeedCompileErrorCheck => unreachable, |
| 166 | else => |e| return e, |
| 167 | }; |
| 168 | |
| 169 | maker.generatedPath(conf_oc.output_file).* = dest_path; |
| 138 | 170 | |
| 139 | | conf_oc.output_file.path = full_dest_path; |
| 140 | | if (conf_oc.output_file_debug) |*file| file.path = full_dest_path_debug; |
| 141 | | try man.writeManifest(); |
| 171 | man.writeManifest() catch |err| switch (err) { |
| 172 | error.Canceled => |e| return e, |
| 173 | else => |e| try step.addError(maker, "failed writing cache manifest: {t}", .{e}), |
| 174 | }; |
| 142 | 175 | } |