| ... | ... | @@ -10,9 +10,10 @@ const math = std.math; |
| 10 | 10 | const mem = std.mem; |
| 11 | 11 | const fat = @import("fat.zig"); |
| 12 | 12 | const commands = @import("commands.zig"); |
| 13 | const tapi = @import("../tapi.zig"); |
| 13 | 14 | |
| 14 | 15 | const Allocator = mem.Allocator; |
| 15 | | const LibStub = @import("../tapi.zig").LibStub; |
| 16 | const LibStub = tapi.LibStub; |
| 16 | 17 | const LoadCommand = commands.LoadCommand; |
| 17 | 18 | const MachO = @import("../MachO.zig"); |
| 18 | 19 | |
| ... | ... | @@ -315,9 +316,9 @@ fn parseSymbols(self: *Dylib, allocator: *Allocator) !void { |
| 315 | 316 | } |
| 316 | 317 | } |
| 317 | 318 | |
| 318 | | fn hasTarget(targets: []const []const u8, target: []const u8) bool { |
| 319 | | for (targets) |t| { |
| 320 | | if (mem.eql(u8, t, target)) return true; |
| 319 | fn hasValue(stack: []const []const u8, needle: []const u8) bool { |
| 320 | for (stack) |v| { |
| 321 | if (mem.eql(u8, v, needle)) return true; |
| 321 | 322 | } |
| 322 | 323 | return false; |
| 323 | 324 | } |
| ... | ... | @@ -334,6 +335,78 @@ fn addObjCClassSymbols(self: *Dylib, allocator: *Allocator, sym_name: []const u8 |
| 334 | 335 | } |
| 335 | 336 | } |
| 336 | 337 | |
| 338 | fn hasArch(archs: []const []const u8, arch: []const u8) bool { |
| 339 | for (archs) |x| { |
| 340 | if (mem.eql(u8, x, arch)) return true; |
| 341 | } |
| 342 | return false; |
| 343 | } |
| 344 | |
| 345 | fn parseFromStubV3(self: *Dylib, allocator: *Allocator, target: std.Target, lib_stub: LibStub) !void { |
| 346 | var umbrella_libs = std.StringHashMap(void).init(allocator); |
| 347 | defer umbrella_libs.deinit(); |
| 348 | |
| 349 | const arch_string = @tagName(target.cpu.arch); |
| 350 | |
| 351 | for (lib_stub.inner) |elem, stub_index| { |
| 352 | const stub = elem.v3; |
| 353 | if (!hasArch(stub.archs, arch_string)) continue; |
| 354 | |
| 355 | if (stub_index > 0) { |
| 356 | // TODO I thought that we could switch on presence of `parent-umbrella` map; |
| 357 | // however, turns out `libsystem_notify.dylib` is fully reexported by `libSystem.dylib` |
| 358 | // BUT does not feature a `parent-umbrella` map as the only sublib. Apple's bug perhaps? |
| 359 | try umbrella_libs.put(stub.install_name, .{}); |
| 360 | } |
| 361 | |
| 362 | if (stub.exports) |exports| { |
| 363 | for (exports) |exp| { |
| 364 | if (!hasArch(exp.archs, arch_string)) continue; |
| 365 | |
| 366 | if (exp.symbols) |symbols| { |
| 367 | for (symbols) |sym_name| { |
| 368 | if (self.symbols.contains(sym_name)) continue; |
| 369 | try self.symbols.putNoClobber(allocator, try allocator.dupe(u8, sym_name), {}); |
| 370 | } |
| 371 | } |
| 372 | |
| 373 | if (exp.re_exports) |re_exports| { |
| 374 | for (re_exports) |reexp| { |
| 375 | if (self.symbols.contains(reexp)) continue; |
| 376 | try self.symbols.putNoClobber(allocator, try allocator.dupe(u8, reexp), {}); |
| 377 | } |
| 378 | } |
| 379 | } |
| 380 | } |
| 381 | } |
| 382 | |
| 383 | log.debug("{s}", .{lib_stub.inner[0].installName()}); |
| 384 | |
| 385 | // // TODO track which libs were already parsed in different steps |
| 386 | // for (lib_stub.inner) |elem| { |
| 387 | // const stub = elem.v3; |
| 388 | // if (!archMatches(stub.archs, arch_string)) continue; |
| 389 | |
| 390 | // if (stub.reexported_libraries) |reexports| { |
| 391 | // for (reexports) |reexp| { |
| 392 | // if (!matcher.matches(reexp.targets)) continue; |
| 393 | |
| 394 | // for (reexp.libraries) |lib| { |
| 395 | // if (umbrella_libs.contains(lib)) { |
| 396 | // log.debug(" | {s} <= {s}", .{ lib, umbrella_lib.install_name }); |
| 397 | // continue; |
| 398 | // } |
| 399 | |
| 400 | // log.debug(" | {s}", .{lib}); |
| 401 | |
| 402 | // const dep_id = try Id.default(allocator, lib); |
| 403 | // try self.dependent_libs.append(allocator, dep_id); |
| 404 | // } |
| 405 | // } |
| 406 | // } |
| 407 | // } |
| 408 | } |
| 409 | |
| 337 | 410 | fn targetToAppleString(allocator: *Allocator, target: std.Target) ![]const u8 { |
| 338 | 411 | const arch = switch (target.cpu.arch) { |
| 339 | 412 | .aarch64 => "arm64", |
| ... | ... | @@ -380,6 +453,13 @@ const TargetMatcher = struct { |
| 380 | 453 | self.target_strings.deinit(self.allocator); |
| 381 | 454 | } |
| 382 | 455 | |
| 456 | fn hasTarget(targets: []const []const u8, target: []const u8) bool { |
| 457 | for (targets) |x| { |
| 458 | if (mem.eql(u8, x, target)) return true; |
| 459 | } |
| 460 | return false; |
| 461 | } |
| 462 | |
| 383 | 463 | fn matches(self: TargetMatcher, targets: []const []const u8) bool { |
| 384 | 464 | for (self.target_strings.items) |t| { |
| 385 | 465 | if (hasTarget(targets, t)) return true; |
| ... | ... | @@ -388,29 +468,15 @@ const TargetMatcher = struct { |
| 388 | 468 | } |
| 389 | 469 | }; |
| 390 | 470 | |
| 391 | | pub fn parseFromStub(self: *Dylib, allocator: *Allocator, target: std.Target, lib_stub: LibStub) !void { |
| 392 | | if (lib_stub.inner.len == 0) return error.EmptyStubFile; |
| 393 | | |
| 394 | | log.debug("parsing shared library from stub '{s}'", .{self.name}); |
| 395 | | |
| 396 | | const umbrella_lib = lib_stub.inner[0]; |
| 397 | | |
| 398 | | var id = try Id.default(allocator, umbrella_lib.install_name); |
| 399 | | if (umbrella_lib.current_version) |version| { |
| 400 | | try id.parseCurrentVersion(version); |
| 401 | | } |
| 402 | | if (umbrella_lib.compatibility_version) |version| { |
| 403 | | try id.parseCompatibilityVersion(version); |
| 404 | | } |
| 405 | | self.id = id; |
| 406 | | |
| 471 | fn parseFromStubV4(self: *Dylib, allocator: *Allocator, target: std.Target, lib_stub: LibStub) !void { |
| 407 | 472 | var matcher = try TargetMatcher.init(allocator, target); |
| 408 | 473 | defer matcher.deinit(); |
| 409 | 474 | |
| 410 | 475 | var umbrella_libs = std.StringHashMap(void).init(allocator); |
| 411 | 476 | defer umbrella_libs.deinit(); |
| 412 | 477 | |
| 413 | | for (lib_stub.inner) |stub, stub_index| { |
| 478 | for (lib_stub.inner) |elem, stub_index| { |
| 479 | const stub = elem.v4; |
| 414 | 480 | if (!matcher.matches(stub.targets)) continue; |
| 415 | 481 | |
| 416 | 482 | if (stub_index > 0) { |
| ... | ... | @@ -465,10 +531,11 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, target: std.Target, li |
| 465 | 531 | } |
| 466 | 532 | } |
| 467 | 533 | |
| 468 | | log.debug("{s}", .{umbrella_lib.install_name}); |
| 534 | log.debug("{s}", .{lib_stub.inner[0].installName()}); |
| 469 | 535 | |
| 470 | 536 | // TODO track which libs were already parsed in different steps |
| 471 | | for (lib_stub.inner) |stub| { |
| 537 | for (lib_stub.inner) |elem| { |
| 538 | const stub = elem.v4; |
| 472 | 539 | if (!matcher.matches(stub.targets)) continue; |
| 473 | 540 | |
| 474 | 541 | if (stub.reexported_libraries) |reexports| { |
| ... | ... | @@ -477,7 +544,7 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, target: std.Target, li |
| 477 | 544 | |
| 478 | 545 | for (reexp.libraries) |lib| { |
| 479 | 546 | if (umbrella_libs.contains(lib)) { |
| 480 | | log.debug(" | {s} <= {s}", .{ lib, umbrella_lib.install_name }); |
| 547 | log.debug(" | {s} <= {s}", .{ lib, lib_stub.inner[0].installName() }); |
| 481 | 548 | continue; |
| 482 | 549 | } |
| 483 | 550 | |
| ... | ... | @@ -491,6 +558,28 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, target: std.Target, li |
| 491 | 558 | } |
| 492 | 559 | } |
| 493 | 560 | |
| 561 | pub fn parseFromStub(self: *Dylib, allocator: *Allocator, target: std.Target, lib_stub: LibStub) !void { |
| 562 | if (lib_stub.inner.len == 0) return error.EmptyStubFile; |
| 563 | |
| 564 | log.debug("parsing shared library from stub '{s}'", .{self.name}); |
| 565 | |
| 566 | const umbrella_lib = lib_stub.inner[0]; |
| 567 | |
| 568 | var id = try Id.default(allocator, umbrella_lib.installName()); |
| 569 | if (umbrella_lib.currentVersion()) |version| { |
| 570 | try id.parseCurrentVersion(version); |
| 571 | } |
| 572 | if (umbrella_lib.compatibilityVersion()) |version| { |
| 573 | try id.parseCompatibilityVersion(version); |
| 574 | } |
| 575 | self.id = id; |
| 576 | |
| 577 | switch (umbrella_lib) { |
| 578 | .v3 => try self.parseFromStubV3(allocator, target, lib_stub), |
| 579 | .v4 => try self.parseFromStubV4(allocator, target, lib_stub), |
| 580 | } |
| 581 | } |
| 582 | |
| 494 | 583 | pub fn parseDependentLibs( |
| 495 | 584 | self: *Dylib, |
| 496 | 585 | allocator: *Allocator, |