authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-05-17 07:19:15-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-05-17 07:19:15-07:00
logc1add1e19ea35b4d96fbab317410276f757510ef
tree9791032b09046f6d5b785cd643439b266737cab4
parent5b06daf52bdeaf18b40909ef878e8b19b3d14019
parent728ce2d7c18e23ca6c36d86f4ee1ea4ce3ac81e2
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15459 from motiejus/build-id-full

stage2: implement `--build-id` styles

9 files changed, 210 insertions(+), 56 deletions(-)

build.zig+7-1
......@@ -165,8 +165,14 @@ pub fn build(b: *std.Build) !void {
165165 exe.strip = strip;
166166 exe.pie = pie;
167167 exe.sanitize_thread = sanitize_thread;
168 exe.build_id = b.option(bool, "build-id", "Include a build id note") orelse false;
169168 exe.entitlements = entitlements;
169
170 exe.build_id = b.option(
171 std.Build.Step.Compile.BuildId,
172 "build-id",
173 "Request creation of '.note.gnu.build-id' section",
174 );
175
170176 b.installArtifact(exe);
171177
172178 test_step.dependOn(&exe.step);
lib/std/Build.zig+42-20
......@@ -181,6 +181,7 @@ const TypeId = enum {
181181 @"enum",
182182 string,
183183 list,
184 build_id,
184185};
185186
186187const TopLevelStep = struct {
......@@ -832,13 +833,13 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_
832833 } else if (mem.eql(u8, s, "false")) {
833834 return false;
834835 } else {
835 log.err("Expected -D{s} to be a boolean, but received '{s}'\n", .{ name, s });
836 log.err("Expected -D{s} to be a boolean, but received '{s}'", .{ name, s });
836837 self.markInvalidUserInput();
837838 return null;
838839 }
839840 },
840841 .list, .map => {
841 log.err("Expected -D{s} to be a boolean, but received a {s}.\n", .{
842 log.err("Expected -D{s} to be a boolean, but received a {s}.", .{
842843 name, @tagName(option_ptr.value),
843844 });
844845 self.markInvalidUserInput();
......@@ -847,7 +848,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_
847848 },
848849 .int => switch (option_ptr.value) {
849850 .flag, .list, .map => {
850 log.err("Expected -D{s} to be an integer, but received a {s}.\n", .{
851 log.err("Expected -D{s} to be an integer, but received a {s}.", .{
851852 name, @tagName(option_ptr.value),
852853 });
853854 self.markInvalidUserInput();
......@@ -856,12 +857,12 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_
856857 .scalar => |s| {
857858 const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) {
858859 error.Overflow => {
859 log.err("-D{s} value {s} cannot fit into type {s}.\n", .{ name, s, @typeName(T) });
860 log.err("-D{s} value {s} cannot fit into type {s}.", .{ name, s, @typeName(T) });
860861 self.markInvalidUserInput();
861862 return null;
862863 },
863864 else => {
864 log.err("Expected -D{s} to be an integer of type {s}.\n", .{ name, @typeName(T) });
865 log.err("Expected -D{s} to be an integer of type {s}.", .{ name, @typeName(T) });
865866 self.markInvalidUserInput();
866867 return null;
867868 },
......@@ -871,7 +872,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_
871872 },
872873 .float => switch (option_ptr.value) {
873874 .flag, .map, .list => {
874 log.err("Expected -D{s} to be a float, but received a {s}.\n", .{
875 log.err("Expected -D{s} to be a float, but received a {s}.", .{
875876 name, @tagName(option_ptr.value),
876877 });
877878 self.markInvalidUserInput();
......@@ -879,7 +880,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_
879880 },
880881 .scalar => |s| {
881882 const n = std.fmt.parseFloat(T, s) catch {
882 log.err("Expected -D{s} to be a float of type {s}.\n", .{ name, @typeName(T) });
883 log.err("Expected -D{s} to be a float of type {s}.", .{ name, @typeName(T) });
883884 self.markInvalidUserInput();
884885 return null;
885886 };
......@@ -888,7 +889,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_
888889 },
889890 .@"enum" => switch (option_ptr.value) {
890891 .flag, .map, .list => {
891 log.err("Expected -D{s} to be an enum, but received a {s}.\n", .{
892 log.err("Expected -D{s} to be an enum, but received a {s}.", .{
892893 name, @tagName(option_ptr.value),
893894 });
894895 self.markInvalidUserInput();
......@@ -898,7 +899,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_
898899 if (std.meta.stringToEnum(T, s)) |enum_lit| {
899900 return enum_lit;
900901 } else {
901 log.err("Expected -D{s} to be of type {s}.\n", .{ name, @typeName(T) });
902 log.err("Expected -D{s} to be of type {s}.", .{ name, @typeName(T) });
902903 self.markInvalidUserInput();
903904 return null;
904905 }
......@@ -906,7 +907,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_
906907 },
907908 .string => switch (option_ptr.value) {
908909 .flag, .list, .map => {
909 log.err("Expected -D{s} to be a string, but received a {s}.\n", .{
910 log.err("Expected -D{s} to be a string, but received a {s}.", .{
910911 name, @tagName(option_ptr.value),
911912 });
912913 self.markInvalidUserInput();
......@@ -914,9 +915,27 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_
914915 },
915916 .scalar => |s| return s,
916917 },
918 .build_id => switch (option_ptr.value) {
919 .flag, .map, .list => {
920 log.err("Expected -D{s} to be an enum, but received a {s}.", .{
921 name, @tagName(option_ptr.value),
922 });
923 self.markInvalidUserInput();
924 return null;
925 },
926 .scalar => |s| {
927 if (Step.Compile.BuildId.parse(s)) |build_id| {
928 return build_id;
929 } else |err| {
930 log.err("unable to parse option '-D{s}': {s}", .{ name, @errorName(err) });
931 self.markInvalidUserInput();
932 return null;
933 }
934 },
935 },
917936 .list => switch (option_ptr.value) {
918937 .flag, .map => {
919 log.err("Expected -D{s} to be a list, but received a {s}.\n", .{
938 log.err("Expected -D{s} to be a list, but received a {s}.", .{
920939 name, @tagName(option_ptr.value),
921940 });
922941 self.markInvalidUserInput();
......@@ -1183,15 +1202,18 @@ pub fn addUserInputFlag(self: *Build, name_raw: []const u8) !bool {
11831202}
11841203
11851204fn typeToEnum(comptime T: type) TypeId {
1186 return switch (@typeInfo(T)) {
1187 .Int => .int,
1188 .Float => .float,
1189 .Bool => .bool,
1190 .Enum => .@"enum",
1191 else => switch (T) {
1192 []const u8 => .string,
1193 []const []const u8 => .list,
1194 else => @compileError("Unsupported type: " ++ @typeName(T)),
1205 return switch (T) {
1206 Step.Compile.BuildId => .build_id,
1207 else => return switch (@typeInfo(T)) {
1208 .Int => .int,
1209 .Float => .float,
1210 .Bool => .bool,
1211 .Enum => .@"enum",
1212 else => switch (T) {
1213 []const u8 => .string,
1214 []const []const u8 => .list,
1215 else => @compileError("Unsupported type: " ++ @typeName(T)),
1216 },
11951217 },
11961218 };
11971219}
lib/std/Build/Cache.zig+4
......@@ -235,6 +235,10 @@ pub const HashHelper = struct {
235235 .none => {},
236236 }
237237 },
238 std.Build.Step.Compile.BuildId => switch (x) {
239 .none, .fast, .uuid, .sha1, .md5 => hh.add(std.meta.activeTag(x)),
240 .hexstring => |hex_string| hh.addBytes(hex_string.toSlice()),
241 },
238242 else => switch (@typeInfo(@TypeOf(x))) {
239243 .Bool, .Int, .Enum, .Array => hh.addBytes(mem.asBytes(&x)),
240244 else => @compileError("unable to hash type " ++ @typeName(@TypeOf(x))),
lib/std/Build/Step/Compile.zig+86-2
......@@ -116,7 +116,7 @@ each_lib_rpath: ?bool = null,
116116/// As an example, the bloaty project refuses to work unless its inputs have
117117/// build ids, in order to prevent accidental mismatches.
118118/// The default is to not include this section because it slows down linking.
119build_id: ?bool = null,
119build_id: ?BuildId = null,
120120
121121/// Create a .eh_frame_hdr section and a PT_GNU_EH_FRAME segment in the ELF
122122/// file.
......@@ -288,6 +288,82 @@ pub const Options = struct {
288288 use_lld: ?bool = null,
289289};
290290
291pub const BuildId = union(enum) {
292 none,
293 fast,
294 uuid,
295 sha1,
296 md5,
297 hexstring: HexString,
298
299 pub fn eql(a: BuildId, b: BuildId) bool {
300 const a_tag = std.meta.activeTag(a);
301 const b_tag = std.meta.activeTag(b);
302 if (a_tag != b_tag) return false;
303 return switch (a) {
304 .none, .fast, .uuid, .sha1, .md5 => true,
305 .hexstring => |a_hexstring| mem.eql(u8, a_hexstring.toSlice(), b.hexstring.toSlice()),
306 };
307 }
308
309 pub const HexString = struct {
310 bytes: [32]u8,
311 len: u8,
312
313 /// Result is byte values, *not* hex-encoded.
314 pub fn toSlice(hs: *const HexString) []const u8 {
315 return hs.bytes[0..hs.len];
316 }
317 };
318
319 /// Input is byte values, *not* hex-encoded.
320 /// Asserts `bytes` fits inside `HexString`
321 pub fn initHexString(bytes: []const u8) BuildId {
322 var result: BuildId = .{ .hexstring = .{
323 .bytes = undefined,
324 .len = @intCast(u8, bytes.len),
325 } };
326 @memcpy(result.hexstring.bytes[0..bytes.len], bytes);
327 return result;
328 }
329
330 /// Converts UTF-8 text to a `BuildId`.
331 pub fn parse(text: []const u8) !BuildId {
332 if (mem.eql(u8, text, "none")) {
333 return .none;
334 } else if (mem.eql(u8, text, "fast")) {
335 return .fast;
336 } else if (mem.eql(u8, text, "uuid")) {
337 return .uuid;
338 } else if (mem.eql(u8, text, "sha1") or mem.eql(u8, text, "tree")) {
339 return .sha1;
340 } else if (mem.eql(u8, text, "md5")) {
341 return .md5;
342 } else if (mem.startsWith(u8, text, "0x")) {
343 var result: BuildId = .{ .hexstring = undefined };
344 const slice = try std.fmt.hexToBytes(&result.hexstring.bytes, text[2..]);
345 result.hexstring.len = @intCast(u8, slice.len);
346 return result;
347 }
348 return error.InvalidBuildIdStyle;
349 }
350
351 test parse {
352 try std.testing.expectEqual(BuildId.md5, try parse("md5"));
353 try std.testing.expectEqual(BuildId.none, try parse("none"));
354 try std.testing.expectEqual(BuildId.fast, try parse("fast"));
355 try std.testing.expectEqual(BuildId.uuid, try parse("uuid"));
356 try std.testing.expectEqual(BuildId.sha1, try parse("sha1"));
357 try std.testing.expectEqual(BuildId.sha1, try parse("tree"));
358
359 try std.testing.expect(BuildId.initHexString("").eql(try parse("0x")));
360 try std.testing.expect(BuildId.initHexString("\x12\x34\x56").eql(try parse("0x123456")));
361 try std.testing.expectError(error.InvalidLength, parse("0x12-34"));
362 try std.testing.expectError(error.InvalidCharacter, parse("0xfoobbb"));
363 try std.testing.expectError(error.InvalidBuildIdStyle, parse("yaddaxxx"));
364 }
365};
366
291367pub const Kind = enum {
292368 exe,
293369 lib,
......@@ -1810,7 +1886,15 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
18101886
18111887 try addFlag(&zig_args, "valgrind", self.valgrind_support);
18121888 try addFlag(&zig_args, "each-lib-rpath", self.each_lib_rpath);
1813 try addFlag(&zig_args, "build-id", self.build_id);
1889
1890 if (self.build_id) |build_id| {
1891 try zig_args.append(switch (build_id) {
1892 .hexstring => |hs| b.fmt("--build-id=0x{s}", .{
1893 std.fmt.fmtSliceHexLower(hs.toSlice()),
1894 }),
1895 .none, .fast, .uuid, .sha1, .md5 => b.fmt("--build-id={s}", .{@tagName(build_id)}),
1896 });
1897 }
18141898
18151899 if (self.zig_lib_dir) |dir| {
18161900 try zig_args.append("--zig-lib-dir");
src/Compilation.zig+4-3
......@@ -29,6 +29,7 @@ const wasi_libc = @import("wasi_libc.zig");
2929const fatal = @import("main.zig").fatal;
3030const clangMain = @import("main.zig").clangMain;
3131const Module = @import("Module.zig");
32const BuildId = std.Build.CompileStep.BuildId;
3233const Cache = std.Build.Cache;
3334const translate_c = @import("translate_c.zig");
3435const clang = @import("clang.zig");
......@@ -563,7 +564,7 @@ pub const InitOptions = struct {
563564 linker_print_map: bool = false,
564565 linker_opt_bisect_limit: i32 = -1,
565566 each_lib_rpath: ?bool = null,
566 build_id: ?bool = null,
567 build_id: ?BuildId = null,
567568 disable_c_depfile: bool = false,
568569 linker_z_nodelete: bool = false,
569570 linker_z_notext: bool = false,
......@@ -797,7 +798,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
797798 const unwind_tables = options.want_unwind_tables orelse
798799 (link_libunwind or target_util.needUnwindTables(options.target));
799800 const link_eh_frame_hdr = options.link_eh_frame_hdr or unwind_tables;
800 const build_id = options.build_id orelse false;
801 const build_id = options.build_id orelse .none;
801802
802803 // Make a decision on whether to use LLD or our own linker.
803804 const use_lld = options.use_lld orelse blk: {
......@@ -828,7 +829,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
828829 options.output_mode == .Lib or
829830 options.linker_script != null or options.version_script != null or
830831 options.emit_implib != null or
831 build_id or
832 build_id != .none or
832833 options.symbol_wrap_set.count() > 0)
833834 {
834835 break :blk true;
src/link.zig+2-1
......@@ -10,6 +10,7 @@ const wasi_libc = @import("wasi_libc.zig");
1010
1111const Air = @import("Air.zig");
1212const Allocator = std.mem.Allocator;
13const BuildId = std.Build.CompileStep.BuildId;
1314const Cache = std.Build.Cache;
1415const Compilation = @import("Compilation.zig");
1516const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
......@@ -157,7 +158,7 @@ pub const Options = struct {
157158 skip_linker_dependencies: bool,
158159 parent_compilation_link_libc: bool,
159160 each_lib_rpath: bool,
160 build_id: bool,
161 build_id: BuildId,
161162 disable_lld_caching: bool,
162163 is_test: bool,
163164 hash_style: HashStyle,
src/link/Elf.zig+12-2
......@@ -1542,8 +1542,18 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
15421542 try argv.append("-z");
15431543 try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size}));
15441544
1545 if (self.base.options.build_id) {
1546 try argv.append("--build-id");
1545 switch (self.base.options.build_id) {
1546 .none => {},
1547 .fast, .uuid, .sha1, .md5 => {
1548 try argv.append(try std.fmt.allocPrint(arena, "--build-id={s}", .{
1549 @tagName(self.base.options.build_id),
1550 }));
1551 },
1552 .hexstring => |hs| {
1553 try argv.append(try std.fmt.allocPrint(arena, "--build-id=0x{s}", .{
1554 std.fmt.fmtSliceHexLower(hs.toSlice()),
1555 }));
1556 },
15471557 }
15481558 }
15491559
src/link/Wasm.zig+29-16
......@@ -3797,8 +3797,29 @@ fn writeToFile(
37973797 if (!wasm.base.options.strip) {
37983798 // The build id must be computed on the main sections only,
37993799 // so we have to do it now, before the debug sections.
3800 if (wasm.base.options.build_id) {
3801 try emitBuildIdSection(&binary_bytes);
3800 switch (wasm.base.options.build_id) {
3801 .none => {},
3802 .fast => {
3803 var id: [16]u8 = undefined;
3804 std.crypto.hash.sha3.TurboShake128(null).hash(binary_bytes.items, &id, .{});
3805 var uuid: [36]u8 = undefined;
3806 _ = try std.fmt.bufPrint(&uuid, "{s}-{s}-{s}-{s}-{s}", .{
3807 std.fmt.fmtSliceHexLower(id[0..4]),
3808 std.fmt.fmtSliceHexLower(id[4..6]),
3809 std.fmt.fmtSliceHexLower(id[6..8]),
3810 std.fmt.fmtSliceHexLower(id[8..10]),
3811 std.fmt.fmtSliceHexLower(id[10..]),
3812 });
3813 try emitBuildIdSection(&binary_bytes, &uuid);
3814 },
3815 .hexstring => |hs| {
3816 var buffer: [32 * 2]u8 = undefined;
3817 const str = std.fmt.bufPrint(&buffer, "{s}", .{
3818 std.fmt.fmtSliceHexLower(hs.toSlice()),
3819 }) catch unreachable;
3820 try emitBuildIdSection(&binary_bytes, str);
3821 },
3822 else => |mode| log.err("build-id '{s}' is not supported for WASM", .{@tagName(mode)}),
38023823 }
38033824
38043825 // if (wasm.dwarf) |*dwarf| {
......@@ -3942,25 +3963,17 @@ fn emitProducerSection(binary_bytes: *std.ArrayList(u8)) !void {
39423963 );
39433964}
39443965
3945fn emitBuildIdSection(binary_bytes: *std.ArrayList(u8)) !void {
3966fn emitBuildIdSection(binary_bytes: *std.ArrayList(u8), build_id: []const u8) !void {
39463967 const header_offset = try reserveCustomSectionHeader(binary_bytes);
39473968
39483969 const writer = binary_bytes.writer();
3949 const build_id = "build_id";
3950 try leb.writeULEB128(writer, @intCast(u32, build_id.len));
3951 try writer.writeAll(build_id);
3952
3953 var id: [16]u8 = undefined;
3954 std.crypto.hash.sha3.TurboShake128(null).hash(binary_bytes.items, &id, .{});
3955 var uuid: [36]u8 = undefined;
3956 _ = try std.fmt.bufPrint(&uuid, "{s}-{s}-{s}-{s}-{s}", .{
3957 std.fmt.fmtSliceHexLower(id[0..4]), std.fmt.fmtSliceHexLower(id[4..6]), std.fmt.fmtSliceHexLower(id[6..8]),
3958 std.fmt.fmtSliceHexLower(id[8..10]), std.fmt.fmtSliceHexLower(id[10..]),
3959 });
3970 const hdr_build_id = "build_id";
3971 try leb.writeULEB128(writer, @intCast(u32, hdr_build_id.len));
3972 try writer.writeAll(hdr_build_id);
39603973
39613974 try leb.writeULEB128(writer, @as(u32, 1));
3962 try leb.writeULEB128(writer, @as(u32, uuid.len));
3963 try writer.writeAll(&uuid);
3975 try leb.writeULEB128(writer, @intCast(u32, build_id.len));
3976 try writer.writeAll(build_id);
39643977
39653978 try writeCustomSectionHeader(
39663979 binary_bytes.items,
src/main.zig+24-11
......@@ -22,6 +22,7 @@ const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
2222const wasi_libc = @import("wasi_libc.zig");
2323const translate_c = @import("translate_c.zig");
2424const clang = @import("clang.zig");
25const BuildId = std.Build.CompileStep.BuildId;
2526const Cache = std.Build.Cache;
2627const target_util = @import("target.zig");
2728const crash_report = @import("crash_report.zig");
......@@ -493,8 +494,10 @@ const usage_build_generic =
493494 \\ -fno-each-lib-rpath Prevent adding rpath for each used dynamic library
494495 \\ -fallow-shlib-undefined Allows undefined symbols in shared libraries
495496 \\ -fno-allow-shlib-undefined Disallows undefined symbols in shared libraries
496 \\ -fbuild-id Helps coordinate stripped binaries with debug symbols
497 \\ -fno-build-id (default) Saves a bit of time linking
497 \\ --build-id[=style] At a minor link-time expense, coordinates stripped binaries
498 \\ fast, uuid, sha1, md5 with debug symbols via a '.note.gnu.build-id' section
499 \\ 0x[hexstring] Maximum 32 bytes
500 \\ none (default) Disable build-id
498501 \\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker
499502 \\ --emit-relocs Enable output of relocation sections for post build tools
500503 \\ -z [arg] Set linker extension flags
......@@ -817,7 +820,7 @@ fn buildOutputType(
817820 var link_eh_frame_hdr = false;
818821 var link_emit_relocs = false;
819822 var each_lib_rpath: ?bool = null;
820 var build_id: ?bool = null;
823 var build_id: ?BuildId = null;
821824 var sysroot: ?[]const u8 = null;
822825 var libc_paths_file: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LIBC");
823826 var machine_code_model: std.builtin.CodeModel = .default;
......@@ -1202,10 +1205,6 @@ fn buildOutputType(
12021205 each_lib_rpath = true;
12031206 } else if (mem.eql(u8, arg, "-fno-each-lib-rpath")) {
12041207 each_lib_rpath = false;
1205 } else if (mem.eql(u8, arg, "-fbuild-id")) {
1206 build_id = true;
1207 } else if (mem.eql(u8, arg, "-fno-build-id")) {
1208 build_id = false;
12091208 } else if (mem.eql(u8, arg, "--test-cmd-bin")) {
12101209 try test_exec_args.append(null);
12111210 } else if (mem.eql(u8, arg, "--test-evented-io")) {
......@@ -1446,6 +1445,15 @@ fn buildOutputType(
14461445 linker_gc_sections = true;
14471446 } else if (mem.eql(u8, arg, "--no-gc-sections")) {
14481447 linker_gc_sections = false;
1448 } else if (mem.eql(u8, arg, "--build-id")) {
1449 build_id = .fast;
1450 } else if (mem.startsWith(u8, arg, "--build-id=")) {
1451 const style = arg["--build-id=".len..];
1452 build_id = BuildId.parse(style) catch |err| {
1453 fatal("unable to parse --build-id style '{s}': {s}", .{
1454 style, @errorName(err),
1455 });
1456 };
14491457 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
14501458 if (!crash_report.is_enabled) {
14511459 std.log.warn("Zig was compiled in a release mode. --debug-compile-errors has no effect.", .{});
......@@ -1684,9 +1692,12 @@ fn buildOutputType(
16841692 if (mem.indexOfScalar(u8, linker_arg, '=')) |equals_pos| {
16851693 const key = linker_arg[0..equals_pos];
16861694 const value = linker_arg[equals_pos + 1 ..];
1687 if (mem.eql(u8, key, "build-id")) {
1688 build_id = true;
1689 warn("ignoring build-id style argument: '{s}'", .{value});
1695 if (mem.eql(u8, key, "--build-id")) {
1696 build_id = BuildId.parse(value) catch |err| {
1697 fatal("unable to parse --build-id style '{s}': {s}", .{
1698 value, @errorName(err),
1699 });
1700 };
16901701 continue;
16911702 } else if (mem.eql(u8, key, "--sort-common")) {
16921703 // this ignores --sort=common=<anything>; ignoring plain --sort-common
......@@ -1698,7 +1709,9 @@ fn buildOutputType(
16981709 continue;
16991710 }
17001711 }
1701 if (mem.eql(u8, linker_arg, "--as-needed")) {
1712 if (mem.eql(u8, linker_arg, "--build-id")) {
1713 build_id = .fast;
1714 } else if (mem.eql(u8, linker_arg, "--as-needed")) {
17021715 needed = false;
17031716 } else if (mem.eql(u8, linker_arg, "--no-as-needed")) {
17041717 needed = true;