| 1 | const ObjCopy = @This(); |
| 2 | |
| 3 | const std = @import("std"); |
| 4 | const Step = std.Build.Step; |
| 5 | const Configuration = std.Build.Configuration; |
| 6 | |
| 7 | step: Step, |
| 8 | input_file: std.Build.LazyPath, |
| 9 | basename: Configuration.OptionalString, |
| 10 | output_file: Configuration.GeneratedFileIndex, |
| 11 | debug_file: ?DebugFile, |
| 12 | |
| 13 | format: ?Format, |
| 14 | only_section: Configuration.OptionalString, |
| 15 | pad_to: ?u64, |
| 16 | strip: Strip, |
| 17 | compress_debug: bool, |
| 18 | |
| 19 | add_sections: std.ArrayList(AddSection) = .empty, |
| 20 | update_sections: std.ArrayList(Configuration.Step.ObjCopy.UpdateSection) = .empty, |
| 21 | |
| 22 | pub const base_tag: Step.Tag = .obj_copy; |
| 23 | |
| 24 | pub const Format = enum { binary, hex, elf }; |
| 25 | pub const Strip = Configuration.Step.ObjCopy.Strip; |
| 26 | pub const SectionFlags = Configuration.Step.ObjCopy.SectionFlags; |
| 27 | |
| 28 | pub const AddSection = struct { |
| 29 | section_name: Configuration.String, |
| 30 | file_path: std.Build.LazyPath, |
| 31 | }; |
| 32 | |
| 33 | pub const DebugFile = struct { |
| 34 | basename: Configuration.OptionalString, |
| 35 | output_file: Configuration.GeneratedFileIndex, |
| 36 | }; |
| 37 | |
| 38 | pub const Options = struct { |
| 39 | basename: ?[]const u8 = null, |
| 40 | format: ?Format = null, |
| 41 | only_section: ?[]const u8 = null, |
| 42 | pad_to: ?u64 = null, |
| 43 | |
| 44 | compress_debug: bool = false, |
| 45 | strip: Strip = .none, |
| 46 | |
| 47 | /// Put the stripped out debug sections in a separate file. |
| 48 | /// note: the `basename` is baked into the elf file to specify the link to the separate debug file. |
| 49 | /// see https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html |
| 50 | /// |
| 51 | /// Makes `getOutputSeparatedDebug` return non-null. |
| 52 | separate_debug_file: ?SeparateDebugFile = null, |
| 53 | |
| 54 | pub const SeparateDebugFile = struct { |
| 55 | basename: ?[]const u8, |
| 56 | }; |
| 57 | }; |
| 58 | |
| 59 | pub fn create(owner: *std.Build, input_file: std.Build.LazyPath, options: Options) *ObjCopy { |
| 60 | const graph = owner.graph; |
| 61 | const wc = &graph.wip_configuration; |
| 62 | const oc = graph.create(ObjCopy); |
| 63 | oc.* = .{ |
| 64 | .step = .init(.{ |
| 65 | .tag = base_tag, |
| 66 | .name = owner.fmt("objcopy {f}", .{input_file}), |
| 67 | .owner = owner, |
| 68 | }), |
| 69 | .input_file = input_file, |
| 70 | .basename = if (options.basename) |s| .init(wc.addString(s) catch @panic("OOM")) else .none, |
| 71 | .output_file = graph.addGeneratedFile(&oc.step), |
| 72 | .debug_file = if (options.separate_debug_file) |df| .{ |
| 73 | .basename = if (df.basename) |s| .init(wc.addString(s) catch @panic("OOM")) else .none, |
| 74 | .output_file = graph.addGeneratedFile(&oc.step), |
| 75 | } else null, |
| 76 | .format = options.format, |
| 77 | .only_section = if (options.only_section) |s| .init(wc.addString(s) catch @panic("OOM")) else .none, |
| 78 | .pad_to = options.pad_to, |
| 79 | .strip = options.strip, |
| 80 | .compress_debug = options.compress_debug, |
| 81 | }; |
| 82 | input_file.addStepDependencies(&oc.step); |
| 83 | return oc; |
| 84 | } |
| 85 | |
| 86 | pub const UpdateSectionOptions = struct { |
| 87 | alignment: ?std.mem.Alignment = null, |
| 88 | flags: SectionFlags = .default, |
| 89 | }; |
| 90 | |
| 91 | pub fn updateSection(oc: *ObjCopy, section_name: []const u8, options: UpdateSectionOptions) void { |
| 92 | const graph = oc.step.owner.graph; |
| 93 | const arena = graph.arena; |
| 94 | const wc = &graph.wip_configuration; |
| 95 | oc.update_sections.append(arena, .{ |
| 96 | .flags = .{ |
| 97 | .section_flags = options.flags, |
| 98 | .alignment = .init(options.alignment), |
| 99 | }, |
| 100 | .section_name = wc.addString(section_name) catch @panic("OOM"), |
| 101 | }) catch @panic("OOM"); |
| 102 | } |
| 103 | |
| 104 | pub const AddSectionOptions = struct { |
| 105 | file_path: std.Build.LazyPath, |
| 106 | }; |
| 107 | |
| 108 | pub fn addSection(oc: *ObjCopy, section_name: []const u8, options: AddSectionOptions) void { |
| 109 | const graph = oc.step.owner.graph; |
| 110 | const arena = graph.arena; |
| 111 | const wc = &graph.wip_configuration; |
| 112 | oc.add_sections.append(arena, .{ |
| 113 | .section_name = wc.addString(section_name) catch @panic("OOM"), |
| 114 | .file_path = options.file_path, |
| 115 | }) catch @panic("OOM"); |
| 116 | options.file_path.addStepDependencies(&oc.step); |
| 117 | } |
| 118 | |
| 119 | pub fn getOutput(oc: *const ObjCopy) std.Build.LazyPath { |
| 120 | return .{ .generated = .{ .index = oc.output_file } }; |
| 121 | } |
| 122 | |
| 123 | pub fn getOutputSeparatedDebug(oc: *const ObjCopy) ?std.Build.LazyPath { |
| 124 | const df = oc.debug_file orelse return null; |
| 125 | return .{ .generated = .{ .index = df.output_file } }; |
| 126 | } |