authorgravatar for xavierb@gmail.comXavier Bouchoux <xavierb@gmail.com> 2023-08-12 06:50:10+00:00
committergravatar for xavierb@gmail.comXavier Bouchoux <xavierb@gmail.com> 2023-08-12 09:54:35+02:00
log2da28d93dec0e9e484076def63e690384a4a5b1f
treee30aad29afc3c65b1b32dd192113e520718825b0
parentaecc15391a4c37a4504d29cb7e3179990b180773

build/ObjCopy: strip debug info to a separate elf file.

example usage: if (!strip) { b.installArtifact(exe); } else { const stripped_exe = b.addObjCopy(exe.getEmittedBin(), .{ .basename = exe.out_filename, // set the name for the debuglink .compress_debug = true, .strip = .debug_and_symbols, .extract_to_separate_file = true, }); b.getInstallStep().dependOn(&b.addInstallBinFile(stripped_exe.getOutput(), exe.out_filename).step); b.getInstallStep().dependOn(&b.addInstallBinFile(stripped_exe.getOutputSeparatedDebug().?, b.fmt("{s}.debug", .{exe.out_filename})).step); }

1 files changed, 47 insertions(+), 2 deletions(-)

lib/std/Build/Step/ObjCopy.zig+47-2
...@@ -17,22 +17,40 @@ pub const base_id: Step.Id = .objcopy;...@@ -17,22 +17,40 @@ pub const base_id: Step.Id = .objcopy;
17pub const RawFormat = enum {17pub const RawFormat = enum {
18 bin,18 bin,
19 hex,19 hex,
20 elf,
21};
22
23pub const Strip = enum {
24 none,
25 debug,
26 debug_and_symbols,
20};27};
2128
22step: Step,29step: Step,
23input_file: std.Build.LazyPath,30input_file: std.Build.LazyPath,
24basename: []const u8,31basename: []const u8,
25output_file: std.Build.GeneratedFile,32output_file: std.Build.GeneratedFile,
33output_file_debug: ?std.Build.GeneratedFile,
2634
27format: ?RawFormat,35format: ?RawFormat,
28only_section: ?[]const u8,36only_section: ?[]const u8,
29pad_to: ?u64,37pad_to: ?u64,
38strip: Strip,
39compress_debug: bool,
3040
31pub const Options = struct {41pub const Options = struct {
32 basename: ?[]const u8 = null,42 basename: ?[]const u8 = null,
33 format: ?RawFormat = null,43 format: ?RawFormat = null,
34 only_section: ?[]const u8 = null,44 only_section: ?[]const u8 = null,
35 pad_to: ?u64 = null,45 pad_to: ?u64 = null,
46
47 compress_debug: bool = false,
48 strip: Strip = .none,
49
50 /// Put the stripped out debug sections in a separate file.
51 /// note: the `basename` is baked into the elf file to specify the link to the separate debug file.
52 /// see https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
53 extract_to_separate_file: bool = false,
36};54};
3755
38pub fn create(56pub fn create(
...@@ -51,10 +69,12 @@ pub fn create(...@@ -51,10 +69,12 @@ pub fn create(
51 .input_file = input_file,69 .input_file = input_file,
52 .basename = options.basename orelse input_file.getDisplayName(),70 .basename = options.basename orelse input_file.getDisplayName(),
53 .output_file = std.Build.GeneratedFile{ .step = &self.step },71 .output_file = std.Build.GeneratedFile{ .step = &self.step },
5472 .output_file_debug = if (options.strip != .none and options.extract_to_separate_file) std.Build.GeneratedFile{ .step = &self.step } else null,
55 .format = options.format,73 .format = options.format,
56 .only_section = options.only_section,74 .only_section = options.only_section,
57 .pad_to = options.pad_to,75 .pad_to = options.pad_to,
76 .strip = options.strip,
77 .compress_debug = options.compress_debug,
58 };78 };
59 input_file.addStepDependencies(&self.step);79 input_file.addStepDependencies(&self.step);
60 return self;80 return self;
...@@ -66,6 +86,9 @@ pub const getOutputSource = getOutput;...@@ -66,6 +86,9 @@ pub const getOutputSource = getOutput;
66pub fn getOutput(self: *const ObjCopy) std.Build.LazyPath {86pub fn getOutput(self: *const ObjCopy) std.Build.LazyPath {
67 return .{ .generated = &self.output_file };87 return .{ .generated = &self.output_file };
68}88}
89pub fn getOutputSeparatedDebug(self: *const ObjCopy) ?std.Build.LazyPath {
90 return if (self.output_file_debug) |*file| .{ .generated = file } else null;
91}
6992
70fn make(step: *Step, prog_node: *std.Progress.Node) !void {93fn make(step: *Step, prog_node: *std.Progress.Node) !void {
71 const b = step.owner;94 const b = step.owner;
...@@ -83,6 +106,9 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {...@@ -83,6 +106,9 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
83 man.hash.addOptionalBytes(self.only_section);106 man.hash.addOptionalBytes(self.only_section);
84 man.hash.addOptional(self.pad_to);107 man.hash.addOptional(self.pad_to);
85 man.hash.addOptional(self.format);108 man.hash.addOptional(self.format);
109 man.hash.add(self.compress_debug);
110 man.hash.add(self.strip);
111 man.hash.add(self.output_file_debug != null);
86112
87 if (try step.cacheHit(&man)) {113 if (try step.cacheHit(&man)) {
88 // Cache hit, skip subprocess execution.114 // Cache hit, skip subprocess execution.
...@@ -90,12 +116,18 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {...@@ -90,12 +116,18 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
90 self.output_file.path = try b.cache_root.join(b.allocator, &.{116 self.output_file.path = try b.cache_root.join(b.allocator, &.{
91 "o", &digest, self.basename,117 "o", &digest, self.basename,
92 });118 });
119 if (self.output_file_debug) |*file| {
120 file.path = try b.cache_root.join(b.allocator, &.{
121 "o", &digest, b.fmt("{s}.debug", .{self.basename}),
122 });
123 }
93 return;124 return;
94 }125 }
95126
96 const digest = man.final();127 const digest = man.final();
97 const full_dest_path = try b.cache_root.join(b.allocator, &.{ "o", &digest, self.basename });
98 const cache_path = "o" ++ fs.path.sep_str ++ digest;128 const cache_path = "o" ++ fs.path.sep_str ++ digest;
129 const full_dest_path = try b.cache_root.join(b.allocator, &.{ cache_path, self.basename });
130 const full_dest_path_debug = try b.cache_root.join(b.allocator, &.{ cache_path, b.fmt("{s}.debug", .{self.basename}) });
99 b.cache_root.handle.makePath(cache_path) catch |err| {131 b.cache_root.handle.makePath(cache_path) catch |err| {
100 return step.fail("unable to make path {s}: {s}", .{ cache_path, @errorName(err) });132 return step.fail("unable to make path {s}: {s}", .{ cache_path, @errorName(err) });
101 };133 };
...@@ -106,13 +138,25 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {...@@ -106,13 +138,25 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
106 if (self.only_section) |only_section| {138 if (self.only_section) |only_section| {
107 try argv.appendSlice(&.{ "-j", only_section });139 try argv.appendSlice(&.{ "-j", only_section });
108 }140 }
141 switch (self.strip) {
142 .none => {},
143 .debug => try argv.appendSlice(&.{"--strip-debug"}),
144 .debug_and_symbols => try argv.appendSlice(&.{"--strip-all"}),
145 }
109 if (self.pad_to) |pad_to| {146 if (self.pad_to) |pad_to| {
110 try argv.appendSlice(&.{ "--pad-to", b.fmt("{d}", .{pad_to}) });147 try argv.appendSlice(&.{ "--pad-to", b.fmt("{d}", .{pad_to}) });
111 }148 }
112 if (self.format) |format| switch (format) {149 if (self.format) |format| switch (format) {
113 .bin => try argv.appendSlice(&.{ "-O", "binary" }),150 .bin => try argv.appendSlice(&.{ "-O", "binary" }),
114 .hex => try argv.appendSlice(&.{ "-O", "hex" }),151 .hex => try argv.appendSlice(&.{ "-O", "hex" }),
152 .elf => try argv.appendSlice(&.{ "-O", "elf" }),
115 };153 };
154 if (self.compress_debug) {
155 try argv.appendSlice(&.{"--compress-debug-sections"});
156 }
157 if (self.output_file_debug != null) {
158 try argv.appendSlice(&.{b.fmt("--extract-to={s}", .{full_dest_path_debug})});
159 }
116160
117 try argv.appendSlice(&.{ full_src_path, full_dest_path });161 try argv.appendSlice(&.{ full_src_path, full_dest_path });
118162
...@@ -120,5 +164,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {...@@ -120,5 +164,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
120 _ = try step.evalZigProcess(argv.items, prog_node);164 _ = try step.evalZigProcess(argv.items, prog_node);
121165
122 self.output_file.path = full_dest_path;166 self.output_file.path = full_dest_path;
167 if (self.output_file_debug) |*file| file.path = full_dest_path_debug;
123 try man.writeManifest();168 try man.writeManifest();
124}169}