| author | |
| committer | |
| log | 728ce2d7c18e23ca6c36d86f4ee1ea4ce3ac81e2 |
| tree | b84ffae450a01a7fa2cf22d87176fb633125b359 |
| parent | df5085bde012773b974f58e8ee28ed90ff686468 |
* 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 parsing9 files changed, 169 insertions(+), 164 deletions(-)
build.zig+5-2| ... | @@ -167,8 +167,11 @@ pub fn build(b: *std.Build) !void { | ... | @@ -167,8 +167,11 @@ pub fn build(b: *std.Build) !void { |
| 167 | exe.sanitize_thread = sanitize_thread; | 167 | exe.sanitize_thread = sanitize_thread; |
| 168 | exe.entitlements = entitlements; | 168 | exe.entitlements = entitlements; |
| 169 | 169 | ||
| 170 | if (b.option([]const u8, "build-id", "Include a build id note")) |build_id| | 170 | exe.build_id = b.option( |
| 171 | exe.build_id = try std.Build.CompileStep.BuildId.parse(b.allocator, build_id); | 171 | std.Build.Step.Compile.BuildId, |
| 172 | "build-id", | ||
| 173 | "Request creation of '.note.gnu.build-id' section", | ||
| 174 | ); | ||
| 172 | 175 | ||
| 173 | b.installArtifact(exe); | 176 | b.installArtifact(exe); |
| 174 | 177 |
lib/std/Build.zig+42-20| ... | @@ -181,6 +181,7 @@ const TypeId = enum { | ... | @@ -181,6 +181,7 @@ const TypeId = enum { |
| 181 | @"enum", | 181 | @"enum", |
| 182 | string, | 182 | string, |
| 183 | list, | 183 | list, |
| 184 | build_id, | ||
| 184 | }; | 185 | }; |
| 185 | 186 | ||
| 186 | const TopLevelStep = struct { | 187 | const TopLevelStep = struct { |
| ... | @@ -832,13 +833,13 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ | ... | @@ -832,13 +833,13 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ |
| 832 | } else if (mem.eql(u8, s, "false")) { | 833 | } else if (mem.eql(u8, s, "false")) { |
| 833 | return false; | 834 | return false; |
| 834 | } else { | 835 | } 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 }); |
| 836 | self.markInvalidUserInput(); | 837 | self.markInvalidUserInput(); |
| 837 | return null; | 838 | return null; |
| 838 | } | 839 | } |
| 839 | }, | 840 | }, |
| 840 | .list, .map => { | 841 | .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}.", .{ |
| 842 | name, @tagName(option_ptr.value), | 843 | name, @tagName(option_ptr.value), |
| 843 | }); | 844 | }); |
| 844 | self.markInvalidUserInput(); | 845 | self.markInvalidUserInput(); |
| ... | @@ -847,7 +848,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ | ... | @@ -847,7 +848,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ |
| 847 | }, | 848 | }, |
| 848 | .int => switch (option_ptr.value) { | 849 | .int => switch (option_ptr.value) { |
| 849 | .flag, .list, .map => { | 850 | .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}.", .{ |
| 851 | name, @tagName(option_ptr.value), | 852 | name, @tagName(option_ptr.value), |
| 852 | }); | 853 | }); |
| 853 | self.markInvalidUserInput(); | 854 | self.markInvalidUserInput(); |
| ... | @@ -856,12 +857,12 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ | ... | @@ -856,12 +857,12 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ |
| 856 | .scalar => |s| { | 857 | .scalar => |s| { |
| 857 | const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) { | 858 | const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) { |
| 858 | error.Overflow => { | 859 | 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) }); |
| 860 | self.markInvalidUserInput(); | 861 | self.markInvalidUserInput(); |
| 861 | return null; | 862 | return null; |
| 862 | }, | 863 | }, |
| 863 | else => { | 864 | 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) }); |
| 865 | self.markInvalidUserInput(); | 866 | self.markInvalidUserInput(); |
| 866 | return null; | 867 | return null; |
| 867 | }, | 868 | }, |
| ... | @@ -871,7 +872,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ | ... | @@ -871,7 +872,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ |
| 871 | }, | 872 | }, |
| 872 | .float => switch (option_ptr.value) { | 873 | .float => switch (option_ptr.value) { |
| 873 | .flag, .map, .list => { | 874 | .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}.", .{ |
| 875 | name, @tagName(option_ptr.value), | 876 | name, @tagName(option_ptr.value), |
| 876 | }); | 877 | }); |
| 877 | self.markInvalidUserInput(); | 878 | self.markInvalidUserInput(); |
| ... | @@ -879,7 +880,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ | ... | @@ -879,7 +880,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ |
| 879 | }, | 880 | }, |
| 880 | .scalar => |s| { | 881 | .scalar => |s| { |
| 881 | const n = std.fmt.parseFloat(T, s) catch { | 882 | 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) }); |
| 883 | self.markInvalidUserInput(); | 884 | self.markInvalidUserInput(); |
| 884 | return null; | 885 | return null; |
| 885 | }; | 886 | }; |
| ... | @@ -888,7 +889,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ | ... | @@ -888,7 +889,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ |
| 888 | }, | 889 | }, |
| 889 | .@"enum" => switch (option_ptr.value) { | 890 | .@"enum" => switch (option_ptr.value) { |
| 890 | .flag, .map, .list => { | 891 | .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}.", .{ |
| 892 | name, @tagName(option_ptr.value), | 893 | name, @tagName(option_ptr.value), |
| 893 | }); | 894 | }); |
| 894 | self.markInvalidUserInput(); | 895 | self.markInvalidUserInput(); |
| ... | @@ -898,7 +899,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ | ... | @@ -898,7 +899,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ |
| 898 | if (std.meta.stringToEnum(T, s)) |enum_lit| { | 899 | if (std.meta.stringToEnum(T, s)) |enum_lit| { |
| 899 | return enum_lit; | 900 | return enum_lit; |
| 900 | } else { | 901 | } 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) }); |
| 902 | self.markInvalidUserInput(); | 903 | self.markInvalidUserInput(); |
| 903 | return null; | 904 | return null; |
| 904 | } | 905 | } |
| ... | @@ -906,7 +907,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ | ... | @@ -906,7 +907,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ |
| 906 | }, | 907 | }, |
| 907 | .string => switch (option_ptr.value) { | 908 | .string => switch (option_ptr.value) { |
| 908 | .flag, .list, .map => { | 909 | .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}.", .{ |
| 910 | name, @tagName(option_ptr.value), | 911 | name, @tagName(option_ptr.value), |
| 911 | }); | 912 | }); |
| 912 | self.markInvalidUserInput(); | 913 | self.markInvalidUserInput(); |
| ... | @@ -914,9 +915,27 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ | ... | @@ -914,9 +915,27 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ |
| 914 | }, | 915 | }, |
| 915 | .scalar => |s| return s, | 916 | .scalar => |s| return s, |
| 916 | }, | 917 | }, |
| 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 | }, | ||
| 917 | .list => switch (option_ptr.value) { | 936 | .list => switch (option_ptr.value) { |
| 918 | .flag, .map => { | 937 | .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}.", .{ |
| 920 | name, @tagName(option_ptr.value), | 939 | name, @tagName(option_ptr.value), |
| 921 | }); | 940 | }); |
| 922 | self.markInvalidUserInput(); | 941 | self.markInvalidUserInput(); |
| ... | @@ -1183,15 +1202,18 @@ pub fn addUserInputFlag(self: *Build, name_raw: []const u8) !bool { | ... | @@ -1183,15 +1202,18 @@ pub fn addUserInputFlag(self: *Build, name_raw: []const u8) !bool { |
| 1183 | } | 1202 | } |
| 1184 | 1203 | ||
| 1185 | fn typeToEnum(comptime T: type) TypeId { | 1204 | fn typeToEnum(comptime T: type) TypeId { |
| 1186 | return switch (@typeInfo(T)) { | 1205 | return switch (T) { |
| 1187 | .Int => .int, | 1206 | Step.Compile.BuildId => .build_id, |
| 1188 | .Float => .float, | 1207 | else => return switch (@typeInfo(T)) { |
| 1189 | .Bool => .bool, | 1208 | .Int => .int, |
| 1190 | .Enum => .@"enum", | 1209 | .Float => .float, |
| 1191 | else => switch (T) { | 1210 | .Bool => .bool, |
| 1192 | []const u8 => .string, | 1211 | .Enum => .@"enum", |
| 1193 | []const []const u8 => .list, | 1212 | else => switch (T) { |
| 1194 | else => @compileError("Unsupported type: " ++ @typeName(T)), | 1213 | []const u8 => .string, |
| 1214 | []const []const u8 => .list, | ||
| 1215 | else => @compileError("Unsupported type: " ++ @typeName(T)), | ||
| 1216 | }, | ||
| 1195 | }, | 1217 | }, |
| 1196 | }; | 1218 | }; |
| 1197 | } | 1219 | } |
lib/std/Build/Cache.zig+4| ... | @@ -235,6 +235,10 @@ pub const HashHelper = struct { | ... | @@ -235,6 +235,10 @@ pub const HashHelper = struct { |
| 235 | .none => {}, | 235 | .none => {}, |
| 236 | } | 236 | } |
| 237 | }, | 237 | }, |
| 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 | }, | ||
| 238 | else => switch (@typeInfo(@TypeOf(x))) { | 242 | else => switch (@typeInfo(@TypeOf(x))) { |
| 239 | .Bool, .Int, .Enum, .Array => hh.addBytes(mem.asBytes(&x)), | 243 | .Bool, .Int, .Enum, .Array => hh.addBytes(mem.asBytes(&x)), |
| 240 | else => @compileError("unable to hash type " ++ @typeName(@TypeOf(x))), | 244 | else => @compileError("unable to hash type " ++ @typeName(@TypeOf(x))), |
lib/std/Build/Step/Compile.zig+55-86| ... | @@ -294,27 +294,41 @@ pub const BuildId = union(enum) { | ... | @@ -294,27 +294,41 @@ pub const BuildId = union(enum) { |
| 294 | uuid, | 294 | uuid, |
| 295 | sha1, | 295 | sha1, |
| 296 | md5, | 296 | md5, |
| 297 | hexstring: []const u8, | 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 | } | ||
| 298 | 308 | ||
| 299 | pub fn hash(self: BuildId, hasher: anytype) void { | 309 | pub const HexString = struct { |
| 300 | switch (self) { | 310 | bytes: [32]u8, |
| 301 | .none, .fast, .uuid, .sha1, .md5 => { | 311 | len: u8, |
| 302 | hasher.update(@tagName(self)); | 312 | |
| 303 | }, | 313 | /// Result is byte values, *not* hex-encoded. |
| 304 | .hexstring => |str| { | 314 | pub fn toSlice(hs: *const HexString) []const u8 { |
| 305 | hasher.update("0x"); | 315 | return hs.bytes[0..hs.len]; |
| 306 | hasher.update(str); | ||
| 307 | }, | ||
| 308 | } | 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; | ||
| 309 | } | 328 | } |
| 310 | 329 | ||
| 311 | // parses the incoming BuildId. If returns a hexstring, it is allocated | 330 | /// Converts UTF-8 text to a `BuildId`. |
| 312 | // by the provided allocator. | 331 | pub fn parse(text: []const u8) !BuildId { |
| 313 | pub fn parse(allocator: std.mem.Allocator, text: []const u8) error{ | ||
| 314 | InvalidHexInt, | ||
| 315 | InvalidBuildId, | ||
| 316 | OutOfMemory, | ||
| 317 | }!BuildId { | ||
| 318 | if (mem.eql(u8, text, "none")) { | 332 | if (mem.eql(u8, text, "none")) { |
| 319 | return .none; | 333 | return .none; |
| 320 | } else if (mem.eql(u8, text, "fast")) { | 334 | } else if (mem.eql(u8, text, "fast")) { |
| ... | @@ -326,27 +340,27 @@ pub const BuildId = union(enum) { | ... | @@ -326,27 +340,27 @@ pub const BuildId = union(enum) { |
| 326 | } else if (mem.eql(u8, text, "md5")) { | 340 | } else if (mem.eql(u8, text, "md5")) { |
| 327 | return .md5; | 341 | return .md5; |
| 328 | } else if (mem.startsWith(u8, text, "0x")) { | 342 | } else if (mem.startsWith(u8, text, "0x")) { |
| 329 | var clean_hex_string = try allocator.alloc(u8, text.len); | 343 | var result: BuildId = .{ .hexstring = undefined }; |
| 330 | errdefer allocator.free(clean_hex_string); | 344 | const slice = try std.fmt.hexToBytes(&result.hexstring.bytes, text[2..]); |
| 331 | 345 | result.hexstring.len = @intCast(u8, slice.len); | |
| 332 | var i: usize = 0; | 346 | return result; |
| 333 | for (text["0x".len..]) |c| { | ||
| 334 | if (std.ascii.isHex(c)) { | ||
| 335 | clean_hex_string[i] = c; | ||
| 336 | i += 1; | ||
| 337 | } else if (c == '-' or c == ':') { | ||
| 338 | continue; | ||
| 339 | } else { | ||
| 340 | return error.InvalidHexInt; | ||
| 341 | } | ||
| 342 | } | ||
| 343 | if (i < text.len) | ||
| 344 | _ = allocator.resize(clean_hex_string, i); | ||
| 345 | |||
| 346 | return BuildId{ .hexstring = clean_hex_string[0..i] }; | ||
| 347 | } | 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")); | ||
| 348 | 358 | ||
| 349 | return error.InvalidBuildId; | 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")); | ||
| 350 | } | 364 | } |
| 351 | }; | 365 | }; |
| 352 | 366 | ||
| ... | @@ -1872,11 +1886,13 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -1872,11 +1886,13 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1872 | 1886 | ||
| 1873 | try addFlag(&zig_args, "valgrind", self.valgrind_support); | 1887 | try addFlag(&zig_args, "valgrind", self.valgrind_support); |
| 1874 | try addFlag(&zig_args, "each-lib-rpath", self.each_lib_rpath); | 1888 | try addFlag(&zig_args, "each-lib-rpath", self.each_lib_rpath); |
| 1889 | |||
| 1875 | if (self.build_id) |build_id| { | 1890 | if (self.build_id) |build_id| { |
| 1876 | const fmt_str = "--build-id={s}{s}"; | ||
| 1877 | try zig_args.append(switch (build_id) { | 1891 | try zig_args.append(switch (build_id) { |
| 1878 | .hexstring => |str| try std.fmt.allocPrint(b.allocator, fmt_str, .{ "0x", str }), | 1892 | .hexstring => |hs| b.fmt("--build-id=0x{s}", .{ |
| 1879 | .none, .fast, .uuid, .sha1, .md5 => try std.fmt.allocPrint(b.allocator, fmt_str, .{ "", @tagName(build_id) }), | 1893 | std.fmt.fmtSliceHexLower(hs.toSlice()), |
| 1894 | }), | ||
| 1895 | .none, .fast, .uuid, .sha1, .md5 => b.fmt("--build-id={s}", .{@tagName(build_id)}), | ||
| 1880 | }); | 1896 | }); |
| 1881 | } | 1897 | } |
| 1882 | 1898 | ||
| ... | @@ -2243,50 +2259,3 @@ fn checkCompileErrors(self: *Compile) !void { | ... | @@ -2243,50 +2259,3 @@ fn checkCompileErrors(self: *Compile) !void { |
| 2243 | \\========================================= | 2259 | \\========================================= |
| 2244 | , .{ expected_generated.items, actual_stderr }); | 2260 | , .{ expected_generated.items, actual_stderr }); |
| 2245 | } | 2261 | } |
| 2246 | |||
| 2247 | const testing = std.testing; | ||
| 2248 | |||
| 2249 | test "BuildId.parse" { | ||
| 2250 | const tests = &[_]struct { | ||
| 2251 | []const u8, | ||
| 2252 | ?BuildId, | ||
| 2253 | ?anyerror, | ||
| 2254 | }{ | ||
| 2255 | .{ "0x", BuildId{ .hexstring = "" }, null }, | ||
| 2256 | .{ "0x12-34:", BuildId{ .hexstring = "1234" }, null }, | ||
| 2257 | .{ "0x123456", BuildId{ .hexstring = "123456" }, null }, | ||
| 2258 | .{ "md5", .md5, null }, | ||
| 2259 | .{ "none", .none, null }, | ||
| 2260 | .{ "fast", .fast, null }, | ||
| 2261 | .{ "uuid", .uuid, null }, | ||
| 2262 | .{ "sha1", .sha1, null }, | ||
| 2263 | .{ "tree", .sha1, null }, | ||
| 2264 | .{ "0xfoobbb", null, error.InvalidHexInt }, | ||
| 2265 | .{ "yaddaxxx", null, error.InvalidBuildId }, | ||
| 2266 | }; | ||
| 2267 | |||
| 2268 | for (tests) |tt| { | ||
| 2269 | const input = tt[0]; | ||
| 2270 | const expected = tt[1]; | ||
| 2271 | const expected_err = tt[2]; | ||
| 2272 | |||
| 2273 | _ = (if (expected_err) |err| { | ||
| 2274 | try testing.expectError(err, BuildId.parse(testing.allocator, input)); | ||
| 2275 | } else blk: { | ||
| 2276 | const actual = BuildId.parse(testing.allocator, input) catch |e| break :blk e; | ||
| 2277 | switch (expected.?) { | ||
| 2278 | .hexstring => |expected_str| { | ||
| 2279 | try testing.expectEqualStrings(expected_str, actual.hexstring); | ||
| 2280 | testing.allocator.free(actual.hexstring); | ||
| 2281 | }, | ||
| 2282 | else => try testing.expectEqual(expected.?, actual), | ||
| 2283 | } | ||
| 2284 | }) catch |e| { | ||
| 2285 | std.log.err( | ||
| 2286 | "BuildId.parse failed on {s}: expected {} got {!}", | ||
| 2287 | .{ input, expected.?, e }, | ||
| 2288 | ); | ||
| 2289 | return e; | ||
| 2290 | }; | ||
| 2291 | } | ||
| 2292 | } |
src/Compilation.zig+4-5| ... | @@ -798,6 +798,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { | ... | @@ -798,6 +798,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 798 | const unwind_tables = options.want_unwind_tables orelse | 798 | const unwind_tables = options.want_unwind_tables orelse |
| 799 | (link_libunwind or target_util.needUnwindTables(options.target)); | 799 | (link_libunwind or target_util.needUnwindTables(options.target)); |
| 800 | const link_eh_frame_hdr = options.link_eh_frame_hdr or unwind_tables; | 800 | const link_eh_frame_hdr = options.link_eh_frame_hdr or unwind_tables; |
| 801 | const build_id = options.build_id orelse .none; | ||
| 801 | 802 | ||
| 802 | // Make a decision on whether to use LLD or our own linker. | 803 | // Make a decision on whether to use LLD or our own linker. |
| 803 | const use_lld = options.use_lld orelse blk: { | 804 | const use_lld = options.use_lld orelse blk: { |
| ... | @@ -828,7 +829,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { | ... | @@ -828,7 +829,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 828 | options.output_mode == .Lib or | 829 | options.output_mode == .Lib or |
| 829 | options.linker_script != null or options.version_script != null or | 830 | options.linker_script != null or options.version_script != null or |
| 830 | options.emit_implib != null or | 831 | options.emit_implib != null or |
| 831 | options.build_id != null or | 832 | build_id != .none or |
| 832 | options.symbol_wrap_set.count() > 0) | 833 | options.symbol_wrap_set.count() > 0) |
| 833 | { | 834 | { |
| 834 | break :blk true; | 835 | break :blk true; |
| ... | @@ -1514,7 +1515,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { | ... | @@ -1514,7 +1515,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1514 | .skip_linker_dependencies = options.skip_linker_dependencies, | 1515 | .skip_linker_dependencies = options.skip_linker_dependencies, |
| 1515 | .parent_compilation_link_libc = options.parent_compilation_link_libc, | 1516 | .parent_compilation_link_libc = options.parent_compilation_link_libc, |
| 1516 | .each_lib_rpath = options.each_lib_rpath orelse options.is_native_os, | 1517 | .each_lib_rpath = options.each_lib_rpath orelse options.is_native_os, |
| 1517 | .build_id = options.build_id, | 1518 | .build_id = build_id, |
| 1518 | .cache_mode = cache_mode, | 1519 | .cache_mode = cache_mode, |
| 1519 | .disable_lld_caching = options.disable_lld_caching or cache_mode == .whole, | 1520 | .disable_lld_caching = options.disable_lld_caching or cache_mode == .whole, |
| 1520 | .subsystem = options.subsystem, | 1521 | .subsystem = options.subsystem, |
| ... | @@ -2269,9 +2270,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes | ... | @@ -2269,9 +2270,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes |
| 2269 | man.hash.addListOfBytes(comp.bin_file.options.rpath_list); | 2270 | man.hash.addListOfBytes(comp.bin_file.options.rpath_list); |
| 2270 | man.hash.addListOfBytes(comp.bin_file.options.symbol_wrap_set.keys()); | 2271 | man.hash.addListOfBytes(comp.bin_file.options.symbol_wrap_set.keys()); |
| 2271 | man.hash.add(comp.bin_file.options.each_lib_rpath); | 2272 | man.hash.add(comp.bin_file.options.each_lib_rpath); |
| 2272 | if (comp.bin_file.options.build_id) |build_id| { | 2273 | man.hash.add(comp.bin_file.options.build_id); |
| 2273 | build_id.hash(&man.hash.hasher); | ||
| 2274 | } | ||
| 2275 | man.hash.add(comp.bin_file.options.skip_linker_dependencies); | 2274 | man.hash.add(comp.bin_file.options.skip_linker_dependencies); |
| 2276 | man.hash.add(comp.bin_file.options.z_nodelete); | 2275 | man.hash.add(comp.bin_file.options.z_nodelete); |
| 2277 | man.hash.add(comp.bin_file.options.z_notext); | 2276 | man.hash.add(comp.bin_file.options.z_notext); |
src/link.zig+1-1| ... | @@ -158,7 +158,7 @@ pub const Options = struct { | ... | @@ -158,7 +158,7 @@ pub const Options = struct { |
| 158 | skip_linker_dependencies: bool, | 158 | skip_linker_dependencies: bool, |
| 159 | parent_compilation_link_libc: bool, | 159 | parent_compilation_link_libc: bool, |
| 160 | each_lib_rpath: bool, | 160 | each_lib_rpath: bool, |
| 161 | build_id: ?BuildId, | 161 | build_id: BuildId, |
| 162 | disable_lld_caching: bool, | 162 | disable_lld_caching: bool, |
| 163 | is_test: bool, | 163 | is_test: bool, |
| 164 | hash_style: HashStyle, | 164 | hash_style: HashStyle, |
src/link/Elf.zig+13-8| ... | @@ -1399,8 +1399,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v | ... | @@ -1399,8 +1399,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v |
| 1399 | man.hash.add(self.base.options.each_lib_rpath); | 1399 | man.hash.add(self.base.options.each_lib_rpath); |
| 1400 | if (self.base.options.output_mode == .Exe) { | 1400 | if (self.base.options.output_mode == .Exe) { |
| 1401 | man.hash.add(stack_size); | 1401 | man.hash.add(stack_size); |
| 1402 | if (self.base.options.build_id) |build_id| | 1402 | man.hash.add(self.base.options.build_id); |
| 1403 | build_id.hash(&man.hash.hasher); | ||
| 1404 | } | 1403 | } |
| 1405 | man.hash.addListOfBytes(self.base.options.symbol_wrap_set.keys()); | 1404 | man.hash.addListOfBytes(self.base.options.symbol_wrap_set.keys()); |
| 1406 | man.hash.add(self.base.options.skip_linker_dependencies); | 1405 | 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 | ... | @@ -1543,12 +1542,18 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v |
| 1543 | try argv.append("-z"); | 1542 | try argv.append("-z"); |
| 1544 | try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size})); | 1543 | try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size})); |
| 1545 | 1544 | ||
| 1546 | if (self.base.options.build_id) |build_id| { | 1545 | switch (self.base.options.build_id) { |
| 1547 | const fmt_str = "--build-id={s}{s}"; | 1546 | .none => {}, |
| 1548 | try argv.append(switch (build_id) { | 1547 | .fast, .uuid, .sha1, .md5 => { |
| 1549 | .hexstring => |str| try std.fmt.allocPrint(arena, fmt_str, .{ "0x", str }), | 1548 | try argv.append(try std.fmt.allocPrint(arena, "--build-id={s}", .{ |
| 1550 | .none, .fast, .uuid, .sha1, .md5 => try std.fmt.allocPrint(arena, fmt_str, .{ "", @tagName(build_id) }), | 1549 | @tagName(self.base.options.build_id), |
| 1551 | }); | 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 | }, | ||
| 1552 | } | 1557 | } |
| 1553 | } | 1558 | } |
| 1554 | 1559 |
src/link/Wasm.zig+25-25| ... | @@ -3163,8 +3163,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l | ... | @@ -3163,8 +3163,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l |
| 3163 | try man.addOptionalFile(compiler_rt_path); | 3163 | try man.addOptionalFile(compiler_rt_path); |
| 3164 | man.hash.addOptionalBytes(options.entry); | 3164 | man.hash.addOptionalBytes(options.entry); |
| 3165 | man.hash.addOptional(options.stack_size_override); | 3165 | man.hash.addOptional(options.stack_size_override); |
| 3166 | if (wasm.base.options.build_id) |build_id| | 3166 | man.hash.add(wasm.base.options.build_id); |
| 3167 | build_id.hash(&man.hash.hasher); | ||
| 3168 | man.hash.add(options.import_memory); | 3167 | man.hash.add(options.import_memory); |
| 3169 | man.hash.add(options.import_table); | 3168 | man.hash.add(options.import_table); |
| 3170 | man.hash.add(options.export_table); | 3169 | man.hash.add(options.export_table); |
| ... | @@ -3798,27 +3797,29 @@ fn writeToFile( | ... | @@ -3798,27 +3797,29 @@ fn writeToFile( |
| 3798 | if (!wasm.base.options.strip) { | 3797 | if (!wasm.base.options.strip) { |
| 3799 | // The build id must be computed on the main sections only, | 3798 | // The build id must be computed on the main sections only, |
| 3800 | // so we have to do it now, before the debug sections. | 3799 | // so we have to do it now, before the debug sections. |
| 3801 | if (wasm.base.options.build_id) |build_id| { | 3800 | switch (wasm.base.options.build_id) { |
| 3802 | switch (build_id) { | 3801 | .none => {}, |
| 3803 | .none => {}, | 3802 | .fast => { |
| 3804 | .fast => { | 3803 | var id: [16]u8 = undefined; |
| 3805 | var id: [16]u8 = undefined; | 3804 | std.crypto.hash.sha3.TurboShake128(null).hash(binary_bytes.items, &id, .{}); |
| 3806 | std.crypto.hash.sha3.TurboShake128(null).hash(binary_bytes.items, &id, .{}); | 3805 | var uuid: [36]u8 = undefined; |
| 3807 | var uuid: [36]u8 = undefined; | 3806 | _ = try std.fmt.bufPrint(&uuid, "{s}-{s}-{s}-{s}-{s}", .{ |
| 3808 | _ = try std.fmt.bufPrint(&uuid, "{s}-{s}-{s}-{s}-{s}", .{ | 3807 | std.fmt.fmtSliceHexLower(id[0..4]), |
| 3809 | std.fmt.fmtSliceHexLower(id[0..4]), | 3808 | std.fmt.fmtSliceHexLower(id[4..6]), |
| 3810 | std.fmt.fmtSliceHexLower(id[4..6]), | 3809 | std.fmt.fmtSliceHexLower(id[6..8]), |
| 3811 | std.fmt.fmtSliceHexLower(id[6..8]), | 3810 | std.fmt.fmtSliceHexLower(id[8..10]), |
| 3812 | std.fmt.fmtSliceHexLower(id[8..10]), | 3811 | std.fmt.fmtSliceHexLower(id[10..]), |
| 3813 | std.fmt.fmtSliceHexLower(id[10..]), | 3812 | }); |
| 3814 | }); | 3813 | try emitBuildIdSection(&binary_bytes, &uuid); |
| 3815 | try emitBuildIdSection(&binary_bytes, &uuid); | 3814 | }, |
| 3816 | }, | 3815 | .hexstring => |hs| { |
| 3817 | .hexstring => |str| { | 3816 | var buffer: [32 * 2]u8 = undefined; |
| 3818 | try emitBuildIdSection(&binary_bytes, str); | 3817 | const str = std.fmt.bufPrint(&buffer, "{s}", .{ |
| 3819 | }, | 3818 | std.fmt.fmtSliceHexLower(hs.toSlice()), |
| 3820 | else => |mode| log.err("build-id '{s}' is not supported for WASM", .{@tagName(mode)}), | 3819 | }) catch unreachable; |
| 3821 | } | 3820 | try emitBuildIdSection(&binary_bytes, str); |
| 3821 | }, | ||
| 3822 | else => |mode| log.err("build-id '{s}' is not supported for WASM", .{@tagName(mode)}), | ||
| 3822 | } | 3823 | } |
| 3823 | 3824 | ||
| 3824 | // if (wasm.dwarf) |*dwarf| { | 3825 | // if (wasm.dwarf) |*dwarf| { |
| ... | @@ -4211,8 +4212,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! | ... | @@ -4211,8 +4212,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! |
| 4211 | try man.addOptionalFile(compiler_rt_path); | 4212 | try man.addOptionalFile(compiler_rt_path); |
| 4212 | man.hash.addOptionalBytes(wasm.base.options.entry); | 4213 | man.hash.addOptionalBytes(wasm.base.options.entry); |
| 4213 | man.hash.addOptional(wasm.base.options.stack_size_override); | 4214 | man.hash.addOptional(wasm.base.options.stack_size_override); |
| 4214 | if (wasm.base.options.build_id) |build_id| | 4215 | man.hash.add(wasm.base.options.build_id); |
| 4215 | build_id.hash(&man.hash.hasher); | ||
| 4216 | man.hash.add(wasm.base.options.import_memory); | 4216 | man.hash.add(wasm.base.options.import_memory); |
| 4217 | man.hash.add(wasm.base.options.import_table); | 4217 | man.hash.add(wasm.base.options.import_table); |
| 4218 | man.hash.add(wasm.base.options.export_table); | 4218 | man.hash.add(wasm.base.options.export_table); |
src/main.zig+20-17| ... | @@ -494,7 +494,10 @@ const usage_build_generic = | ... | @@ -494,7 +494,10 @@ const usage_build_generic = |
| 494 | \\ -fno-each-lib-rpath Prevent adding rpath for each used dynamic library | 494 | \\ -fno-each-lib-rpath Prevent adding rpath for each used dynamic library |
| 495 | \\ -fallow-shlib-undefined Allows undefined symbols in shared libraries | 495 | \\ -fallow-shlib-undefined Allows undefined symbols in shared libraries |
| 496 | \\ -fno-allow-shlib-undefined Disallows undefined symbols in shared libraries | 496 | \\ -fno-allow-shlib-undefined Disallows undefined symbols in shared libraries |
| 497 | \\ --build-id[=style] Generate a build ID note | 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 | ||
| 498 | \\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker | 501 | \\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker |
| 499 | \\ --emit-relocs Enable output of relocation sections for post build tools | 502 | \\ --emit-relocs Enable output of relocation sections for post build tools |
| 500 | \\ -z [arg] Set linker extension flags | 503 | \\ -z [arg] Set linker extension flags |
| ... | @@ -1445,11 +1448,11 @@ fn buildOutputType( | ... | @@ -1445,11 +1448,11 @@ fn buildOutputType( |
| 1445 | } else if (mem.eql(u8, arg, "--build-id")) { | 1448 | } else if (mem.eql(u8, arg, "--build-id")) { |
| 1446 | build_id = .fast; | 1449 | build_id = .fast; |
| 1447 | } else if (mem.startsWith(u8, arg, "--build-id=")) { | 1450 | } else if (mem.startsWith(u8, arg, "--build-id=")) { |
| 1448 | const value = arg["--build-id=".len..]; | 1451 | const style = arg["--build-id=".len..]; |
| 1449 | build_id = BuildId.parse(arena, value) catch |err| switch (err) { | 1452 | build_id = BuildId.parse(style) catch |err| { |
| 1450 | error.InvalidHexInt => fatal("failed to parse hex value {s}", .{value}), | 1453 | fatal("unable to parse --build-id style '{s}': {s}", .{ |
| 1451 | error.InvalidBuildId => fatal("invalid --build-id={s}", .{value}), | 1454 | style, @errorName(err), |
| 1452 | error.OutOfMemory => fatal("OOM", .{}), | 1455 | }); |
| 1453 | }; | 1456 | }; |
| 1454 | } else if (mem.eql(u8, arg, "--debug-compile-errors")) { | 1457 | } else if (mem.eql(u8, arg, "--debug-compile-errors")) { |
| 1455 | if (!crash_report.is_enabled) { | 1458 | if (!crash_report.is_enabled) { |
| ... | @@ -1689,7 +1692,14 @@ fn buildOutputType( | ... | @@ -1689,7 +1692,14 @@ fn buildOutputType( |
| 1689 | if (mem.indexOfScalar(u8, linker_arg, '=')) |equals_pos| { | 1692 | if (mem.indexOfScalar(u8, linker_arg, '=')) |equals_pos| { |
| 1690 | const key = linker_arg[0..equals_pos]; | 1693 | const key = linker_arg[0..equals_pos]; |
| 1691 | const value = linker_arg[equals_pos + 1 ..]; | 1694 | const value = linker_arg[equals_pos + 1 ..]; |
| 1692 | if (mem.eql(u8, key, "--sort-common")) { | 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 | }; | ||
| 1701 | continue; | ||
| 1702 | } else if (mem.eql(u8, key, "--sort-common")) { | ||
| 1693 | // this ignores --sort=common=<anything>; ignoring plain --sort-common | 1703 | // this ignores --sort=common=<anything>; ignoring plain --sort-common |
| 1694 | // is done below. | 1704 | // is done below. |
| 1695 | continue; | 1705 | continue; |
| ... | @@ -1699,7 +1709,9 @@ fn buildOutputType( | ... | @@ -1699,7 +1709,9 @@ fn buildOutputType( |
| 1699 | continue; | 1709 | continue; |
| 1700 | } | 1710 | } |
| 1701 | } | 1711 | } |
| 1702 | 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")) { | ||
| 1703 | needed = false; | 1715 | needed = false; |
| 1704 | } else if (mem.eql(u8, linker_arg, "--no-as-needed")) { | 1716 | } else if (mem.eql(u8, linker_arg, "--no-as-needed")) { |
| 1705 | needed = true; | 1717 | needed = true; |
| ... | @@ -1731,15 +1743,6 @@ fn buildOutputType( | ... | @@ -1731,15 +1743,6 @@ fn buildOutputType( |
| 1731 | search_strategy = .paths_first; | 1743 | search_strategy = .paths_first; |
| 1732 | } else if (mem.eql(u8, linker_arg, "-search_dylibs_first")) { | 1744 | } else if (mem.eql(u8, linker_arg, "-search_dylibs_first")) { |
| 1733 | search_strategy = .dylibs_first; | 1745 | search_strategy = .dylibs_first; |
| 1734 | } else if (mem.eql(u8, linker_arg, "--build-id")) { | ||
| 1735 | build_id = .fast; | ||
| 1736 | } else if (mem.startsWith(u8, linker_arg, "--build-id=")) { | ||
| 1737 | const value = linker_arg["--build-id=".len..]; | ||
| 1738 | build_id = BuildId.parse(arena, value) catch |err| switch (err) { | ||
| 1739 | error.InvalidHexInt => fatal("failed to parse hex value {s}", .{value}), | ||
| 1740 | error.InvalidBuildId => fatal("invalid --build-id={s}", .{value}), | ||
| 1741 | error.OutOfMemory => fatal("OOM", .{}), | ||
| 1742 | }; | ||
| 1743 | } else { | 1746 | } else { |
| 1744 | try linker_args.append(linker_arg); | 1747 | try linker_args.append(linker_arg); |
| 1745 | } | 1748 | } |