| author | |
| committer | |
| log | f821543e4b5e44b2ca3217c189272105fc3effb9 |
| tree | 791536aa3ff2205cdaaa7052ea3dd596db3782ea |
| parent | cb475aa161238ef0d77fc49b13c23f2c4b48bfc5 |
| parent | 960e5c329a5436d1e5748948c5744c1a11ddecbb |
| signature |
macho: fix parsing of TBDv3 dylib stubs6 files changed, 114 insertions(+), 18 deletions(-)
src/link/MachO/Dylib.zig+40-15| ... | ... | @@ -9,12 +9,14 @@ const macho = std.macho; |
| 9 | 9 | const math = std.math; |
| 10 | 10 | const mem = std.mem; |
| 11 | 11 | const fat = @import("fat.zig"); |
| 12 | const tapi = @import("../tapi.zig"); | |
| 12 | 13 | |
| 13 | 14 | const Allocator = mem.Allocator; |
| 14 | 15 | const CrossTarget = std.zig.CrossTarget; |
| 15 | const LibStub = @import("../tapi.zig").LibStub; | |
| 16 | const LibStub = tapi.LibStub; | |
| 16 | 17 | const LoadCommandIterator = macho.LoadCommandIterator; |
| 17 | 18 | const MachO = @import("../MachO.zig"); |
| 19 | const Tbd = tapi.Tbd; | |
| 18 | 20 | |
| 19 | 21 | id: ?Id = null, |
| 20 | 22 | weak: bool = false, |
| ... | ... | @@ -247,7 +249,8 @@ const TargetMatcher = struct { |
| 247 | 249 | .allocator = allocator, |
| 248 | 250 | .target = target, |
| 249 | 251 | }; |
| 250 | try self.target_strings.append(allocator, try targetToAppleString(allocator, target)); | |
| 252 | const apple_string = try targetToAppleString(allocator, target); | |
| 253 | try self.target_strings.append(allocator, apple_string); | |
| 251 | 254 | |
| 252 | 255 | const abi = target.abi orelse .none; |
| 253 | 256 | if (abi == .simulator) { |
| ... | ... | @@ -270,22 +273,29 @@ const TargetMatcher = struct { |
| 270 | 273 | self.target_strings.deinit(self.allocator); |
| 271 | 274 | } |
| 272 | 275 | |
| 273 | fn targetToAppleString(allocator: Allocator, target: CrossTarget) ![]const u8 { | |
| 274 | const cpu_arch = switch (target.cpu_arch.?) { | |
| 276 | inline fn cpuArchToAppleString(cpu_arch: std.Target.Cpu.Arch) []const u8 { | |
| 277 | return switch (cpu_arch) { | |
| 275 | 278 | .aarch64 => "arm64", |
| 276 | 279 | .x86_64 => "x86_64", |
| 277 | 280 | else => unreachable, |
| 278 | 281 | }; |
| 279 | const os_tag = @tagName(target.os_tag.?); | |
| 280 | const target_abi = target.abi orelse .none; | |
| 281 | const abi: ?[]const u8 = switch (target_abi) { | |
| 282 | } | |
| 283 | ||
| 284 | inline fn abiToAppleString(abi: std.Target.Abi) ?[]const u8 { | |
| 285 | return switch (abi) { | |
| 282 | 286 | .none => null, |
| 283 | 287 | .simulator => "simulator", |
| 284 | 288 | .macabi => "maccatalyst", |
| 285 | 289 | else => unreachable, |
| 286 | 290 | }; |
| 287 | if (abi) |x| { | |
| 288 | return std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ cpu_arch, os_tag, x }); | |
| 291 | } | |
| 292 | ||
| 293 | fn targetToAppleString(allocator: Allocator, target: CrossTarget) ![]const u8 { | |
| 294 | const cpu_arch = cpuArchToAppleString(target.cpu_arch.?); | |
| 295 | const os_tag = @tagName(target.os_tag.?); | |
| 296 | const target_abi = abiToAppleString(target.abi orelse .none); | |
| 297 | if (target_abi) |abi| { | |
| 298 | return std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ cpu_arch, os_tag, abi }); | |
| 289 | 299 | } |
| 290 | 300 | return std.fmt.allocPrint(allocator, "{s}-{s}", .{ cpu_arch, os_tag }); |
| 291 | 301 | } |
| ... | ... | @@ -305,7 +315,26 @@ const TargetMatcher = struct { |
| 305 | 315 | } |
| 306 | 316 | |
| 307 | 317 | fn matchesArch(self: TargetMatcher, archs: []const []const u8) bool { |
| 308 | return hasValue(archs, @tagName(self.target.cpu_arch.?)); | |
| 318 | return hasValue(archs, cpuArchToAppleString(self.target.cpu_arch.?)); | |
| 319 | } | |
| 320 | ||
| 321 | fn matchesTargetTbd(self: TargetMatcher, tbd: Tbd) !bool { | |
| 322 | var arena = std.heap.ArenaAllocator.init(self.allocator); | |
| 323 | defer arena.deinit(); | |
| 324 | ||
| 325 | const targets = switch (tbd) { | |
| 326 | .v3 => |v3| blk: { | |
| 327 | var targets = std.ArrayList([]const u8).init(arena.allocator()); | |
| 328 | for (v3.archs) |arch| { | |
| 329 | const target = try std.fmt.allocPrint(arena.allocator(), "{s}-{s}", .{ arch, v3.platform }); | |
| 330 | try targets.append(target); | |
| 331 | } | |
| 332 | break :blk targets.items; | |
| 333 | }, | |
| 334 | .v4 => |v4| v4.targets, | |
| 335 | }; | |
| 336 | ||
| 337 | return self.matchesTarget(targets); | |
| 309 | 338 | } |
| 310 | 339 | }; |
| 311 | 340 | |
| ... | ... | @@ -348,11 +377,7 @@ pub fn parseFromStub( |
| 348 | 377 | defer matcher.deinit(); |
| 349 | 378 | |
| 350 | 379 | for (lib_stub.inner, 0..) |elem, stub_index| { |
| 351 | const is_match = switch (elem) { | |
| 352 | .v3 => |stub| matcher.matchesArch(stub.archs), | |
| 353 | .v4 => |stub| matcher.matchesTarget(stub.targets), | |
| 354 | }; | |
| 355 | if (!is_match) continue; | |
| 380 | if (!(try matcher.matchesTargetTbd(elem))) continue; | |
| 356 | 381 | |
| 357 | 382 | if (stub_index > 0) { |
| 358 | 383 | // TODO I thought that we could switch on presence of `parent-umbrella` map; |
src/link/tapi/yaml.zig+3-3| ... | ... | @@ -197,7 +197,7 @@ pub const Value = union(enum) { |
| 197 | 197 | |
| 198 | 198 | return Value{ .string = try arena.dupe(u8, value.string_value.items) }; |
| 199 | 199 | } else { |
| 200 | log.err("Unexpected node type: {}", .{node.tag}); | |
| 200 | log.debug("Unexpected node type: {}", .{node.tag}); | |
| 201 | 201 | return error.UnexpectedNodeType; |
| 202 | 202 | } |
| 203 | 203 | } |
| ... | ... | @@ -270,7 +270,7 @@ pub const Value = union(enum) { |
| 270 | 270 | if (try encode(arena, elem)) |value| { |
| 271 | 271 | list.appendAssumeCapacity(value); |
| 272 | 272 | } else { |
| 273 | log.err("Could not encode value in a list: {any}", .{elem}); | |
| 273 | log.debug("Could not encode value in a list: {any}", .{elem}); | |
| 274 | 274 | return error.CannotEncodeValue; |
| 275 | 275 | } |
| 276 | 276 | } |
| ... | ... | @@ -432,7 +432,7 @@ pub const Yaml = struct { |
| 432 | 432 | } |
| 433 | 433 | |
| 434 | 434 | const unwrapped = value orelse { |
| 435 | log.err("missing struct field: {s}: {s}", .{ field.name, @typeName(field.type) }); | |
| 435 | log.debug("missing struct field: {s}: {s}", .{ field.name, @typeName(field.type) }); | |
| 436 | 436 | return error.StructFieldMissing; |
| 437 | 437 | }; |
| 438 | 438 | @field(parsed, field.name) = try self.parseValue(field.type, unwrapped); |
test/link.zig+4| ... | ... | @@ -164,6 +164,10 @@ pub const cases = [_]Case{ |
| 164 | 164 | .build_root = "test/link/macho/strict_validation", |
| 165 | 165 | .import = @import("link/macho/strict_validation/build.zig"), |
| 166 | 166 | }, |
| 167 | .{ | |
| 168 | .build_root = "test/link/macho/tbdv3", | |
| 169 | .import = @import("link/macho/tbdv3/build.zig"), | |
| 170 | }, | |
| 167 | 171 | .{ |
| 168 | 172 | .build_root = "test/link/macho/tls", |
| 169 | 173 | .import = @import("link/macho/tls/build.zig"), |
test/link/macho/tbdv3/a.c created+3| ... | ... | @@ -0,0 +1,3 @@ |
| 1 | int getFoo() { | |
| 2 | return 42; | |
| 3 | } |
test/link/macho/tbdv3/build.zig created+57| ... | ... | @@ -0,0 +1,57 @@ |
| 1 | const std = @import("std"); | |
| 2 | const builtin = @import("builtin"); | |
| 3 | ||
| 4 | pub const requires_symlinks = true; | |
| 5 | pub const requires_macos_sdk = false; | |
| 6 | ||
| 7 | pub fn build(b: *std.Build) void { | |
| 8 | const test_step = b.step("test", "Test it"); | |
| 9 | b.default_step = test_step; | |
| 10 | ||
| 11 | add(b, test_step, .Debug); | |
| 12 | add(b, test_step, .ReleaseFast); | |
| 13 | add(b, test_step, .ReleaseSmall); | |
| 14 | add(b, test_step, .ReleaseSafe); | |
| 15 | } | |
| 16 | ||
| 17 | fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void { | |
| 18 | const target: std.zig.CrossTarget = .{ .os_tag = .macos }; | |
| 19 | ||
| 20 | const lib = b.addSharedLibrary(.{ | |
| 21 | .name = "a", | |
| 22 | .version = .{ .major = 1, .minor = 0, .patch = 0 }, | |
| 23 | .optimize = optimize, | |
| 24 | .target = target, | |
| 25 | }); | |
| 26 | lib.addCSourceFile("a.c", &.{}); | |
| 27 | lib.linkLibC(); | |
| 28 | ||
| 29 | const tbd_file = b.addWriteFile("liba.tbd", | |
| 30 | \\--- !tapi-tbd-v3 | |
| 31 | \\archs: [ arm64, x86_64 ] | |
| 32 | \\uuids: [ 'arm64: DEADBEEF', 'x86_64: BEEFDEAD' ] | |
| 33 | \\platform: macos | |
| 34 | \\install-name: @rpath/liba.dylib | |
| 35 | \\current-version: 0 | |
| 36 | \\exports: | |
| 37 | \\ - archs: [ arm64, x86_64 ] | |
| 38 | \\ symbols: [ _getFoo ] | |
| 39 | ); | |
| 40 | ||
| 41 | const exe = b.addExecutable(.{ | |
| 42 | .name = "test", | |
| 43 | .optimize = optimize, | |
| 44 | .target = target, | |
| 45 | }); | |
| 46 | exe.addCSourceFile("main.c", &[0][]const u8{}); | |
| 47 | exe.linkSystemLibrary("a"); | |
| 48 | exe.addLibraryPathDirectorySource(tbd_file.getDirectorySource()); | |
| 49 | exe.addRPathDirectorySource(lib.getOutputDirectorySource()); | |
| 50 | exe.linkLibC(); | |
| 51 | ||
| 52 | const run = b.addRunArtifact(exe); | |
| 53 | run.skip_foreign_checks = true; | |
| 54 | run.expectExitCode(0); | |
| 55 | ||
| 56 | test_step.dependOn(&run.step); | |
| 57 | } |
test/link/macho/tbdv3/main.c created+7| ... | ... | @@ -0,0 +1,7 @@ |
| 1 | #include <stdio.h> | |
| 2 | ||
| 3 | int getFoo(); | |
| 4 | ||
| 5 | int main() { | |
| 6 | return getFoo() - 42; | |
| 7 | } |