From df5085bde012773b974f58e8ee28ed90ff686468 Mon Sep 17 00:00:00 2001 From: Motiejus Jakštys Date: Tue, 25 Apr 2023 16:57:43 +0300 Subject: stage2: implement --build-id styles --- lib/std/Build/Step/Compile.zig | 119 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index 2371f49daf..25492eb73d 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -116,7 +116,7 @@ each_lib_rpath: ?bool = null, /// As an example, the bloaty project refuses to work unless its inputs have /// build ids, in order to prevent accidental mismatches. /// The default is to not include this section because it slows down linking. -build_id: ?bool = null, +build_id: ?BuildId = null, /// Create a .eh_frame_hdr section and a PT_GNU_EH_FRAME segment in the ELF /// file. @@ -288,6 +288,68 @@ pub const Options = struct { use_lld: ?bool = null, }; +pub const BuildId = union(enum) { + none, + fast, + uuid, + sha1, + md5, + hexstring: []const u8, + + pub fn hash(self: BuildId, hasher: anytype) void { + switch (self) { + .none, .fast, .uuid, .sha1, .md5 => { + hasher.update(@tagName(self)); + }, + .hexstring => |str| { + hasher.update("0x"); + hasher.update(str); + }, + } + } + + // parses the incoming BuildId. If returns a hexstring, it is allocated + // by the provided allocator. + pub fn parse(allocator: std.mem.Allocator, text: []const u8) error{ + InvalidHexInt, + InvalidBuildId, + OutOfMemory, + }!BuildId { + if (mem.eql(u8, text, "none")) { + return .none; + } else if (mem.eql(u8, text, "fast")) { + return .fast; + } else if (mem.eql(u8, text, "uuid")) { + return .uuid; + } else if (mem.eql(u8, text, "sha1") or mem.eql(u8, text, "tree")) { + return .sha1; + } else if (mem.eql(u8, text, "md5")) { + return .md5; + } else if (mem.startsWith(u8, text, "0x")) { + var clean_hex_string = try allocator.alloc(u8, text.len); + errdefer allocator.free(clean_hex_string); + + var i: usize = 0; + for (text["0x".len..]) |c| { + if (std.ascii.isHex(c)) { + clean_hex_string[i] = c; + i += 1; + } else if (c == '-' or c == ':') { + continue; + } else { + return error.InvalidHexInt; + } + } + if (i < text.len) + _ = allocator.resize(clean_hex_string, i); + + return BuildId{ .hexstring = clean_hex_string[0..i] }; + } + + return error.InvalidBuildId; + } +}; + pub const Kind = enum { exe, lib, @@ -1810,7 +1872,13 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { try addFlag(&zig_args, "valgrind", self.valgrind_support); try addFlag(&zig_args, "each-lib-rpath", self.each_lib_rpath); - try addFlag(&zig_args, "build-id", self.build_id); + if (self.build_id) |build_id| { + const fmt_str = "--build-id={s}{s}"; + try zig_args.append(switch (build_id) { + .hexstring => |str| try std.fmt.allocPrint(b.allocator, fmt_str, .{ "0x", str }), + .none, .fast, .uuid, .sha1, .md5 => try std.fmt.allocPrint(b.allocator, fmt_str, .{ "", @tagName(build_id) }), + }); + } if (self.zig_lib_dir) |dir| { try zig_args.append("--zig-lib-dir"); @@ -2175,3 +2243,50 @@ fn checkCompileErrors(self: *Compile) !void { \\========================================= , .{ expected_generated.items, actual_stderr }); } + +const testing = std.testing; + +test "BuildId.parse" { + const tests = &[_]struct { + []const u8, + ?BuildId, + ?anyerror, + }{ + .{ "0x", BuildId{ .hexstring = "" }, null }, + .{ "0x12-34:", BuildId{ .hexstring = "1234" }, null }, + .{ "0x123456", BuildId{ .hexstring = "123456" }, null }, + .{ "md5", .md5, null }, + .{ "none", .none, null }, + .{ "fast", .fast, null }, + .{ "uuid", .uuid, null }, + .{ "sha1", .sha1, null }, + .{ "tree", .sha1, null }, + .{ "0xfoobbb", null, error.InvalidHexInt }, + .{ "yaddaxxx", null, error.InvalidBuildId }, + }; + + for (tests) |tt| { + const input = tt[0]; + const expected = tt[1]; + const expected_err = tt[2]; + + _ = (if (expected_err) |err| { + try testing.expectError(err, BuildId.parse(testing.allocator, input)); + } else blk: { + const actual = BuildId.parse(testing.allocator, input) catch |e| break :blk e; + switch (expected.?) { + .hexstring => |expected_str| { + try testing.expectEqualStrings(expected_str, actual.hexstring); + testing.allocator.free(actual.hexstring); + }, + else => try testing.expectEqual(expected.?, actual), + } + }) catch |e| { + std.log.err( + "BuildId.parse failed on {s}: expected {} got {!}", + .{ input, expected.?, e }, + ); + return e; + }; + } +} -- cgit v1.2.3 From 728ce2d7c18e23ca6c36d86f4ee1ea4ce3ac81e2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 16 May 2023 20:00:47 -0700 Subject: tweaks to --build-id * build.zig: the result of b.option() can be assigned directly in many cases thanks to the return type being an optional * std.Build: make the build system aware of the std.Build.Step.Compile.BuildId type when used as an option. - remove extraneous newlines in error logs * simplify caching logic * simplify hexstring parsing tests and use a doc test * simplify hashing logic. don't use an optional when the `none` tag already provides this meaning. * CLI: fix incorrect linker arg parsing --- build.zig | 7 +- lib/std/Build.zig | 62 ++++++++++++------ lib/std/Build/Cache.zig | 4 ++ lib/std/Build/Step/Compile.zig | 141 ++++++++++++++++------------------------- src/Compilation.zig | 9 ++- src/link.zig | 2 +- src/link/Elf.zig | 21 +++--- src/link/Wasm.zig | 50 +++++++-------- src/main.zig | 37 ++++++----- 9 files changed, 169 insertions(+), 164 deletions(-) (limited to 'lib') diff --git a/build.zig b/build.zig index 62f1d86441..a75269083f 100644 --- a/build.zig +++ b/build.zig @@ -167,8 +167,11 @@ pub fn build(b: *std.Build) !void { exe.sanitize_thread = sanitize_thread; exe.entitlements = entitlements; - if (b.option([]const u8, "build-id", "Include a build id note")) |build_id| - exe.build_id = try std.Build.CompileStep.BuildId.parse(b.allocator, build_id); + exe.build_id = b.option( + std.Build.Step.Compile.BuildId, + "build-id", + "Request creation of '.note.gnu.build-id' section", + ); b.installArtifact(exe); diff --git a/lib/std/Build.zig b/lib/std/Build.zig index ca55d23937..7ef504851e 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -181,6 +181,7 @@ const TypeId = enum { @"enum", string, list, + build_id, }; const TopLevelStep = struct { @@ -832,13 +833,13 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ } else if (mem.eql(u8, s, "false")) { return false; } else { - log.err("Expected -D{s} to be a boolean, but received '{s}'\n", .{ name, s }); + log.err("Expected -D{s} to be a boolean, but received '{s}'", .{ name, s }); self.markInvalidUserInput(); return null; } }, .list, .map => { - log.err("Expected -D{s} to be a boolean, but received a {s}.\n", .{ + log.err("Expected -D{s} to be a boolean, but received a {s}.", .{ name, @tagName(option_ptr.value), }); self.markInvalidUserInput(); @@ -847,7 +848,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ }, .int => switch (option_ptr.value) { .flag, .list, .map => { - log.err("Expected -D{s} to be an integer, but received a {s}.\n", .{ + log.err("Expected -D{s} to be an integer, but received a {s}.", .{ name, @tagName(option_ptr.value), }); self.markInvalidUserInput(); @@ -856,12 +857,12 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ .scalar => |s| { const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) { error.Overflow => { - log.err("-D{s} value {s} cannot fit into type {s}.\n", .{ name, s, @typeName(T) }); + log.err("-D{s} value {s} cannot fit into type {s}.", .{ name, s, @typeName(T) }); self.markInvalidUserInput(); return null; }, else => { - log.err("Expected -D{s} to be an integer of type {s}.\n", .{ name, @typeName(T) }); + log.err("Expected -D{s} to be an integer of type {s}.", .{ name, @typeName(T) }); self.markInvalidUserInput(); return null; }, @@ -871,7 +872,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ }, .float => switch (option_ptr.value) { .flag, .map, .list => { - log.err("Expected -D{s} to be a float, but received a {s}.\n", .{ + log.err("Expected -D{s} to be a float, but received a {s}.", .{ name, @tagName(option_ptr.value), }); self.markInvalidUserInput(); @@ -879,7 +880,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ }, .scalar => |s| { const n = std.fmt.parseFloat(T, s) catch { - log.err("Expected -D{s} to be a float of type {s}.\n", .{ name, @typeName(T) }); + log.err("Expected -D{s} to be a float of type {s}.", .{ name, @typeName(T) }); self.markInvalidUserInput(); return null; }; @@ -888,7 +889,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ }, .@"enum" => switch (option_ptr.value) { .flag, .map, .list => { - log.err("Expected -D{s} to be an enum, but received a {s}.\n", .{ + log.err("Expected -D{s} to be an enum, but received a {s}.", .{ name, @tagName(option_ptr.value), }); self.markInvalidUserInput(); @@ -898,7 +899,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ if (std.meta.stringToEnum(T, s)) |enum_lit| { return enum_lit; } else { - log.err("Expected -D{s} to be of type {s}.\n", .{ name, @typeName(T) }); + log.err("Expected -D{s} to be of type {s}.", .{ name, @typeName(T) }); self.markInvalidUserInput(); return null; } @@ -906,7 +907,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ }, .string => switch (option_ptr.value) { .flag, .list, .map => { - log.err("Expected -D{s} to be a string, but received a {s}.\n", .{ + log.err("Expected -D{s} to be a string, but received a {s}.", .{ name, @tagName(option_ptr.value), }); self.markInvalidUserInput(); @@ -914,9 +915,27 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ }, .scalar => |s| return s, }, + .build_id => switch (option_ptr.value) { + .flag, .map, .list => { + log.err("Expected -D{s} to be an enum, but received a {s}.", .{ + name, @tagName(option_ptr.value), + }); + self.markInvalidUserInput(); + return null; + }, + .scalar => |s| { + if (Step.Compile.BuildId.parse(s)) |build_id| { + return build_id; + } else |err| { + log.err("unable to parse option '-D{s}': {s}", .{ name, @errorName(err) }); + self.markInvalidUserInput(); + return null; + } + }, + }, .list => switch (option_ptr.value) { .flag, .map => { - log.err("Expected -D{s} to be a list, but received a {s}.\n", .{ + log.err("Expected -D{s} to be a list, but received a {s}.", .{ name, @tagName(option_ptr.value), }); self.markInvalidUserInput(); @@ -1183,15 +1202,18 @@ pub fn addUserInputFlag(self: *Build, name_raw: []const u8) !bool { } fn typeToEnum(comptime T: type) TypeId { - return switch (@typeInfo(T)) { - .Int => .int, - .Float => .float, - .Bool => .bool, - .Enum => .@"enum", - else => switch (T) { - []const u8 => .string, - []const []const u8 => .list, - else => @compileError("Unsupported type: " ++ @typeName(T)), + return switch (T) { + Step.Compile.BuildId => .build_id, + else => return switch (@typeInfo(T)) { + .Int => .int, + .Float => .float, + .Bool => .bool, + .Enum => .@"enum", + else => switch (T) { + []const u8 => .string, + []const []const u8 => .list, + else => @compileError("Unsupported type: " ++ @typeName(T)), + }, }, }; } diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig index 17429c0370..e991aff5b5 100644 --- a/lib/std/Build/Cache.zig +++ b/lib/std/Build/Cache.zig @@ -235,6 +235,10 @@ pub const HashHelper = struct { .none => {}, } }, + std.Build.Step.Compile.BuildId => switch (x) { + .none, .fast, .uuid, .sha1, .md5 => hh.add(std.meta.activeTag(x)), + .hexstring => |hex_string| hh.addBytes(hex_string.toSlice()), + }, else => switch (@typeInfo(@TypeOf(x))) { .Bool, .Int, .Enum, .Array => hh.addBytes(mem.asBytes(&x)), else => @compileError("unable to hash type " ++ @typeName(@TypeOf(x))), diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index 25492eb73d..d0a2d69bfe 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -294,27 +294,41 @@ pub const BuildId = union(enum) { uuid, sha1, md5, - hexstring: []const u8, + hexstring: HexString, + + pub fn eql(a: BuildId, b: BuildId) bool { + const a_tag = std.meta.activeTag(a); + const b_tag = std.meta.activeTag(b); + if (a_tag != b_tag) return false; + return switch (a) { + .none, .fast, .uuid, .sha1, .md5 => true, + .hexstring => |a_hexstring| mem.eql(u8, a_hexstring.toSlice(), b.hexstring.toSlice()), + }; + } - pub fn hash(self: BuildId, hasher: anytype) void { - switch (self) { - .none, .fast, .uuid, .sha1, .md5 => { - hasher.update(@tagName(self)); - }, - .hexstring => |str| { - hasher.update("0x"); - hasher.update(str); - }, + pub const HexString = struct { + bytes: [32]u8, + len: u8, + + /// Result is byte values, *not* hex-encoded. + pub fn toSlice(hs: *const HexString) []const u8 { + return hs.bytes[0..hs.len]; } + }; + + /// Input is byte values, *not* hex-encoded. + /// Asserts `bytes` fits inside `HexString` + pub fn initHexString(bytes: []const u8) BuildId { + var result: BuildId = .{ .hexstring = .{ + .bytes = undefined, + .len = @intCast(u8, bytes.len), + } }; + @memcpy(result.hexstring.bytes[0..bytes.len], bytes); + return result; } - // parses the incoming BuildId. If returns a hexstring, it is allocated - // by the provided allocator. - pub fn parse(allocator: std.mem.Allocator, text: []const u8) error{ - InvalidHexInt, - InvalidBuildId, - OutOfMemory, - }!BuildId { + /// Converts UTF-8 text to a `BuildId`. + pub fn parse(text: []const u8) !BuildId { if (mem.eql(u8, text, "none")) { return .none; } else if (mem.eql(u8, text, "fast")) { @@ -326,27 +340,27 @@ pub const BuildId = union(enum) { } else if (mem.eql(u8, text, "md5")) { return .md5; } else if (mem.startsWith(u8, text, "0x")) { - var clean_hex_string = try allocator.alloc(u8, text.len); - errdefer allocator.free(clean_hex_string); - - var i: usize = 0; - for (text["0x".len..]) |c| { - if (std.ascii.isHex(c)) { - clean_hex_string[i] = c; - i += 1; - } else if (c == '-' or c == ':') { - continue; - } else { - return error.InvalidHexInt; - } - } - if (i < text.len) - _ = allocator.resize(clean_hex_string, i); - - return BuildId{ .hexstring = clean_hex_string[0..i] }; + var result: BuildId = .{ .hexstring = undefined }; + const slice = try std.fmt.hexToBytes(&result.hexstring.bytes, text[2..]); + result.hexstring.len = @intCast(u8, slice.len); + return result; } + return error.InvalidBuildIdStyle; + } + + test parse { + try std.testing.expectEqual(BuildId.md5, try parse("md5")); + try std.testing.expectEqual(BuildId.none, try parse("none")); + try std.testing.expectEqual(BuildId.fast, try parse("fast")); + try std.testing.expectEqual(BuildId.uuid, try parse("uuid")); + try std.testing.expectEqual(BuildId.sha1, try parse("sha1")); + try std.testing.expectEqual(BuildId.sha1, try parse("tree")); - return error.InvalidBuildId; + try std.testing.expect(BuildId.initHexString("").eql(try parse("0x"))); + try std.testing.expect(BuildId.initHexString("\x12\x34\x56").eql(try parse("0x123456"))); + try std.testing.expectError(error.InvalidLength, parse("0x12-34")); + try std.testing.expectError(error.InvalidCharacter, parse("0xfoobbb")); + try std.testing.expectError(error.InvalidBuildIdStyle, parse("yaddaxxx")); } }; @@ -1872,11 +1886,13 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { try addFlag(&zig_args, "valgrind", self.valgrind_support); try addFlag(&zig_args, "each-lib-rpath", self.each_lib_rpath); + if (self.build_id) |build_id| { - const fmt_str = "--build-id={s}{s}"; try zig_args.append(switch (build_id) { - .hexstring => |str| try std.fmt.allocPrint(b.allocator, fmt_str, .{ "0x", str }), - .none, .fast, .uuid, .sha1, .md5 => try std.fmt.allocPrint(b.allocator, fmt_str, .{ "", @tagName(build_id) }), + .hexstring => |hs| b.fmt("--build-id=0x{s}", .{ + std.fmt.fmtSliceHexLower(hs.toSlice()), + }), + .none, .fast, .uuid, .sha1, .md5 => b.fmt("--build-id={s}", .{@tagName(build_id)}), }); } @@ -2243,50 +2259,3 @@ fn checkCompileErrors(self: *Compile) !void { \\========================================= , .{ expected_generated.items, actual_stderr }); } - -const testing = std.testing; - -test "BuildId.parse" { - const tests = &[_]struct { - []const u8, - ?BuildId, - ?anyerror, - }{ - .{ "0x", BuildId{ .hexstring = "" }, null }, - .{ "0x12-34:", BuildId{ .hexstring = "1234" }, null }, - .{ "0x123456", BuildId{ .hexstring = "123456" }, null }, - .{ "md5", .md5, null }, - .{ "none", .none, null }, - .{ "fast", .fast, null }, - .{ "uuid", .uuid, null }, - .{ "sha1", .sha1, null }, - .{ "tree", .sha1, null }, - .{ "0xfoobbb", null, error.InvalidHexInt }, - .{ "yaddaxxx", null, error.InvalidBuildId }, - }; - - for (tests) |tt| { - const input = tt[0]; - const expected = tt[1]; - const expected_err = tt[2]; - - _ = (if (expected_err) |err| { - try testing.expectError(err, BuildId.parse(testing.allocator, input)); - } else blk: { - const actual = BuildId.parse(testing.allocator, input) catch |e| break :blk e; - switch (expected.?) { - .hexstring => |expected_str| { - try testing.expectEqualStrings(expected_str, actual.hexstring); - testing.allocator.free(actual.hexstring); - }, - else => try testing.expectEqual(expected.?, actual), - } - }) catch |e| { - std.log.err( - "BuildId.parse failed on {s}: expected {} got {!}", - .{ input, expected.?, e }, - ); - return e; - }; - } -} diff --git a/src/Compilation.zig b/src/Compilation.zig index 5a547346a5..de09a78c77 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -798,6 +798,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { const unwind_tables = options.want_unwind_tables orelse (link_libunwind or target_util.needUnwindTables(options.target)); const link_eh_frame_hdr = options.link_eh_frame_hdr or unwind_tables; + const build_id = options.build_id orelse .none; // Make a decision on whether to use LLD or our own linker. const use_lld = options.use_lld orelse blk: { @@ -828,7 +829,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { options.output_mode == .Lib or options.linker_script != null or options.version_script != null or options.emit_implib != null or - options.build_id != null or + build_id != .none or options.symbol_wrap_set.count() > 0) { break :blk true; @@ -1514,7 +1515,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .skip_linker_dependencies = options.skip_linker_dependencies, .parent_compilation_link_libc = options.parent_compilation_link_libc, .each_lib_rpath = options.each_lib_rpath orelse options.is_native_os, - .build_id = options.build_id, + .build_id = build_id, .cache_mode = cache_mode, .disable_lld_caching = options.disable_lld_caching or cache_mode == .whole, .subsystem = options.subsystem, @@ -2269,9 +2270,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes man.hash.addListOfBytes(comp.bin_file.options.rpath_list); man.hash.addListOfBytes(comp.bin_file.options.symbol_wrap_set.keys()); man.hash.add(comp.bin_file.options.each_lib_rpath); - if (comp.bin_file.options.build_id) |build_id| { - build_id.hash(&man.hash.hasher); - } + man.hash.add(comp.bin_file.options.build_id); man.hash.add(comp.bin_file.options.skip_linker_dependencies); man.hash.add(comp.bin_file.options.z_nodelete); man.hash.add(comp.bin_file.options.z_notext); diff --git a/src/link.zig b/src/link.zig index eccf389d05..79ac33b892 100644 --- a/src/link.zig +++ b/src/link.zig @@ -158,7 +158,7 @@ pub const Options = struct { skip_linker_dependencies: bool, parent_compilation_link_libc: bool, each_lib_rpath: bool, - build_id: ?BuildId, + build_id: BuildId, disable_lld_caching: bool, is_test: bool, hash_style: HashStyle, diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 289c687270..f90f4ebd46 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1399,8 +1399,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v man.hash.add(self.base.options.each_lib_rpath); if (self.base.options.output_mode == .Exe) { man.hash.add(stack_size); - if (self.base.options.build_id) |build_id| - build_id.hash(&man.hash.hasher); + man.hash.add(self.base.options.build_id); } man.hash.addListOfBytes(self.base.options.symbol_wrap_set.keys()); man.hash.add(self.base.options.skip_linker_dependencies); @@ -1543,12 +1542,18 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append("-z"); try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size})); - if (self.base.options.build_id) |build_id| { - const fmt_str = "--build-id={s}{s}"; - try argv.append(switch (build_id) { - .hexstring => |str| try std.fmt.allocPrint(arena, fmt_str, .{ "0x", str }), - .none, .fast, .uuid, .sha1, .md5 => try std.fmt.allocPrint(arena, fmt_str, .{ "", @tagName(build_id) }), - }); + switch (self.base.options.build_id) { + .none => {}, + .fast, .uuid, .sha1, .md5 => { + try argv.append(try std.fmt.allocPrint(arena, "--build-id={s}", .{ + @tagName(self.base.options.build_id), + })); + }, + .hexstring => |hs| { + try argv.append(try std.fmt.allocPrint(arena, "--build-id=0x{s}", .{ + std.fmt.fmtSliceHexLower(hs.toSlice()), + })); + }, } } diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 9396377c73..cd9c44d656 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -3163,8 +3163,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l try man.addOptionalFile(compiler_rt_path); man.hash.addOptionalBytes(options.entry); man.hash.addOptional(options.stack_size_override); - if (wasm.base.options.build_id) |build_id| - build_id.hash(&man.hash.hasher); + man.hash.add(wasm.base.options.build_id); man.hash.add(options.import_memory); man.hash.add(options.import_table); man.hash.add(options.export_table); @@ -3798,27 +3797,29 @@ fn writeToFile( if (!wasm.base.options.strip) { // The build id must be computed on the main sections only, // so we have to do it now, before the debug sections. - if (wasm.base.options.build_id) |build_id| { - switch (build_id) { - .none => {}, - .fast => { - var id: [16]u8 = undefined; - std.crypto.hash.sha3.TurboShake128(null).hash(binary_bytes.items, &id, .{}); - var uuid: [36]u8 = undefined; - _ = try std.fmt.bufPrint(&uuid, "{s}-{s}-{s}-{s}-{s}", .{ - std.fmt.fmtSliceHexLower(id[0..4]), - std.fmt.fmtSliceHexLower(id[4..6]), - std.fmt.fmtSliceHexLower(id[6..8]), - std.fmt.fmtSliceHexLower(id[8..10]), - std.fmt.fmtSliceHexLower(id[10..]), - }); - try emitBuildIdSection(&binary_bytes, &uuid); - }, - .hexstring => |str| { - try emitBuildIdSection(&binary_bytes, str); - }, - else => |mode| log.err("build-id '{s}' is not supported for WASM", .{@tagName(mode)}), - } + switch (wasm.base.options.build_id) { + .none => {}, + .fast => { + var id: [16]u8 = undefined; + std.crypto.hash.sha3.TurboShake128(null).hash(binary_bytes.items, &id, .{}); + var uuid: [36]u8 = undefined; + _ = try std.fmt.bufPrint(&uuid, "{s}-{s}-{s}-{s}-{s}", .{ + std.fmt.fmtSliceHexLower(id[0..4]), + std.fmt.fmtSliceHexLower(id[4..6]), + std.fmt.fmtSliceHexLower(id[6..8]), + std.fmt.fmtSliceHexLower(id[8..10]), + std.fmt.fmtSliceHexLower(id[10..]), + }); + try emitBuildIdSection(&binary_bytes, &uuid); + }, + .hexstring => |hs| { + var buffer: [32 * 2]u8 = undefined; + const str = std.fmt.bufPrint(&buffer, "{s}", .{ + std.fmt.fmtSliceHexLower(hs.toSlice()), + }) catch unreachable; + try emitBuildIdSection(&binary_bytes, str); + }, + else => |mode| log.err("build-id '{s}' is not supported for WASM", .{@tagName(mode)}), } // if (wasm.dwarf) |*dwarf| { @@ -4211,8 +4212,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! try man.addOptionalFile(compiler_rt_path); man.hash.addOptionalBytes(wasm.base.options.entry); man.hash.addOptional(wasm.base.options.stack_size_override); - if (wasm.base.options.build_id) |build_id| - build_id.hash(&man.hash.hasher); + man.hash.add(wasm.base.options.build_id); man.hash.add(wasm.base.options.import_memory); man.hash.add(wasm.base.options.import_table); man.hash.add(wasm.base.options.export_table); diff --git a/src/main.zig b/src/main.zig index 93199f9566..aa7d587983 100644 --- a/src/main.zig +++ b/src/main.zig @@ -494,7 +494,10 @@ const usage_build_generic = \\ -fno-each-lib-rpath Prevent adding rpath for each used dynamic library \\ -fallow-shlib-undefined Allows undefined symbols in shared libraries \\ -fno-allow-shlib-undefined Disallows undefined symbols in shared libraries - \\ --build-id[=style] Generate a build ID note + \\ --build-id[=style] At a minor link-time expense, coordinates stripped binaries + \\ fast, uuid, sha1, md5 with debug symbols via a '.note.gnu.build-id' section + \\ 0x[hexstring] Maximum 32 bytes + \\ none (default) Disable build-id \\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker \\ --emit-relocs Enable output of relocation sections for post build tools \\ -z [arg] Set linker extension flags @@ -1445,11 +1448,11 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "--build-id")) { build_id = .fast; } else if (mem.startsWith(u8, arg, "--build-id=")) { - const value = arg["--build-id=".len..]; - build_id = BuildId.parse(arena, value) catch |err| switch (err) { - error.InvalidHexInt => fatal("failed to parse hex value {s}", .{value}), - error.InvalidBuildId => fatal("invalid --build-id={s}", .{value}), - error.OutOfMemory => fatal("OOM", .{}), + const style = arg["--build-id=".len..]; + build_id = BuildId.parse(style) catch |err| { + fatal("unable to parse --build-id style '{s}': {s}", .{ + style, @errorName(err), + }); }; } else if (mem.eql(u8, arg, "--debug-compile-errors")) { if (!crash_report.is_enabled) { @@ -1689,7 +1692,14 @@ fn buildOutputType( if (mem.indexOfScalar(u8, linker_arg, '=')) |equals_pos| { const key = linker_arg[0..equals_pos]; const value = linker_arg[equals_pos + 1 ..]; - if (mem.eql(u8, key, "--sort-common")) { + if (mem.eql(u8, key, "--build-id")) { + build_id = BuildId.parse(value) catch |err| { + fatal("unable to parse --build-id style '{s}': {s}", .{ + value, @errorName(err), + }); + }; + continue; + } else if (mem.eql(u8, key, "--sort-common")) { // this ignores --sort=common=; ignoring plain --sort-common // is done below. continue; @@ -1699,7 +1709,9 @@ fn buildOutputType( continue; } } - if (mem.eql(u8, linker_arg, "--as-needed")) { + if (mem.eql(u8, linker_arg, "--build-id")) { + build_id = .fast; + } else if (mem.eql(u8, linker_arg, "--as-needed")) { needed = false; } else if (mem.eql(u8, linker_arg, "--no-as-needed")) { needed = true; @@ -1731,15 +1743,6 @@ fn buildOutputType( search_strategy = .paths_first; } else if (mem.eql(u8, linker_arg, "-search_dylibs_first")) { search_strategy = .dylibs_first; - } else if (mem.eql(u8, linker_arg, "--build-id")) { - build_id = .fast; - } else if (mem.startsWith(u8, linker_arg, "--build-id=")) { - const value = linker_arg["--build-id=".len..]; - build_id = BuildId.parse(arena, value) catch |err| switch (err) { - error.InvalidHexInt => fatal("failed to parse hex value {s}", .{value}), - error.InvalidBuildId => fatal("invalid --build-id={s}", .{value}), - error.OutOfMemory => fatal("OOM", .{}), - }; } else { try linker_args.append(linker_arg); } -- cgit v1.2.3