1const ObjCopy = @This();
2
3const std = @import("std");
4const Step = std.Build.Step;
5const Configuration = std.Build.Configuration;
6
7step: Step,
8input_file: std.Build.LazyPath,
9basename: Configuration.OptionalString,
10output_file: Configuration.GeneratedFileIndex,
11debug_file: ?DebugFile,
12
13format: ?Format,
14only_section: Configuration.OptionalString,
15pad_to: ?u64,
16strip: Strip,
17compress_debug: bool,
18
19add_sections: std.ArrayList(AddSection) = .empty,
20update_sections: std.ArrayList(Configuration.Step.ObjCopy.UpdateSection) = .empty,
21
22pub const base_tag: Step.Tag = .obj_copy;
23
24pub const Format = enum { binary, hex, elf };
25pub const Strip = Configuration.Step.ObjCopy.Strip;
26pub const SectionFlags = Configuration.Step.ObjCopy.SectionFlags;
27
28pub const AddSection = struct {
29 section_name: Configuration.String,
30 file_path: std.Build.LazyPath,
31};
32
33pub const DebugFile = struct {
34 basename: Configuration.OptionalString,
35 output_file: Configuration.GeneratedFileIndex,
36};
37
38pub 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
59pub 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
86pub const UpdateSectionOptions = struct {
87 alignment: ?std.mem.Alignment = null,
88 flags: SectionFlags = .default,
89};
90
91pub 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
104pub const AddSectionOptions = struct {
105 file_path: std.Build.LazyPath,
106};
107
108pub 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
119pub fn getOutput(oc: *const ObjCopy) std.Build.LazyPath {
120 return .{ .generated = .{ .index = oc.output_file } };
121}
122
123pub 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}