| ... | @@ -514,140 +514,83 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -514,140 +514,83 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 514 | } | 514 | } |
| 515 | } | 515 | } |
| 516 | | 516 | |
| 517 | const LibKind = enum { | 517 | fn resolveSearchDir( |
| 518 | lib, | | |
| 519 | framework, | | |
| 520 | }; | | |
| 521 | | | |
| 522 | fn resolveDirs( | | |
| 523 | arena: *Allocator, | 518 | arena: *Allocator, |
| 524 | resolved_dirs: *std.ArrayList([]const u8), | 519 | dir: []const u8, |
| 525 | syslibroot: ?[]const u8, | 520 | syslibroot: ?[]const u8, |
| 526 | search_dirs: []const []const u8, | 521 | ) !?[]const u8 { |
| 527 | lib_kind: LibKind, | 522 | var candidates = std.ArrayList([]const u8).init(arena); |
| 528 | ) !void { | | |
| 529 | for (search_dirs) |dir| { | | |
| 530 | if (fs.path.isAbsolute(dir)) { | | |
| 531 | var candidates = std.ArrayList([]const u8).init(arena); | | |
| 532 | if (syslibroot) |root| { | | |
| 533 | const full_path = try fs.path.join(arena, &[_][]const u8{ root, dir }); | | |
| 534 | try candidates.append(full_path); | | |
| 535 | } | | |
| 536 | try candidates.append(dir); | | |
| 537 | | | |
| 538 | var found = false; | | |
| 539 | for (candidates.items) |candidate| { | | |
| 540 | // Verify that search path actually exists | | |
| 541 | var tmp = fs.cwd().openDir(candidate, .{}) catch |err| switch (err) { | | |
| 542 | error.FileNotFound => continue, | | |
| 543 | else => |e| return e, | | |
| 544 | }; | | |
| 545 | defer tmp.close(); | | |
| 546 | | 523 | |
| 547 | try resolved_dirs.append(candidate); | 524 | if (fs.path.isAbsolute(dir)) { |
| 548 | found = true; | 525 | if (syslibroot) |root| { |
| 549 | break; | 526 | const full_path = try fs.path.join(arena, &[_][]const u8{ root, dir }); |
| 550 | } | 527 | try candidates.append(full_path); |
| | 528 | } |
| | 529 | } |
| 551 | | 530 | |
| 552 | if (!found) { | 531 | try candidates.append(dir); |
| 553 | switch (lib_kind) { | | |
| 554 | .lib => log.warn("directory not found for '-L{s}'", .{dir}), | | |
| 555 | .framework => log.warn("directory not found for '-F{s}'", .{dir}), | | |
| 556 | } | | |
| 557 | } | | |
| 558 | } else { | | |
| 559 | // Verify that search path actually exists | | |
| 560 | var tmp = fs.cwd().openDir(dir, .{}) catch |err| switch (err) { | | |
| 561 | error.FileNotFound => { | | |
| 562 | switch (lib_kind) { | | |
| 563 | .lib => log.warn("directory not found for '-L{s}'", .{dir}), | | |
| 564 | .framework => log.warn("directory not found for '-F{s}'", .{dir}), | | |
| 565 | } | | |
| 566 | continue; | | |
| 567 | }, | | |
| 568 | else => |e| return e, | | |
| 569 | }; | | |
| 570 | defer tmp.close(); | | |
| 571 | | 532 | |
| 572 | try resolved_dirs.append(dir); | 533 | for (candidates.items) |candidate| { |
| 573 | } | 534 | // Verify that search path actually exists |
| | 535 | var tmp = fs.cwd().openDir(candidate, .{}) catch |err| switch (err) { |
| | 536 | error.FileNotFound => continue, |
| | 537 | else => |e| return e, |
| | 538 | }; |
| | 539 | defer tmp.close(); |
| | 540 | |
| | 541 | return candidate; |
| 574 | } | 542 | } |
| | 543 | |
| | 544 | return null; |
| 575 | } | 545 | } |
| 576 | | 546 | |
| 577 | fn resolveLib( | 547 | fn resolveLib( |
| 578 | arena: *Allocator, | 548 | arena: *Allocator, |
| 579 | lib_dirs: []const []const u8, | 549 | search_dirs: []const []const u8, |
| 580 | lib_name: []const u8, | 550 | name: []const u8, |
| 581 | lib_kind: LibKind, | 551 | ext: []const u8, |
| 582 | ) !?[]const u8 { | 552 | ) !?[]const u8 { |
| 583 | // Assume ld64 default: -search_paths_first | 553 | const search_name = try std.fmt.allocPrint(arena, "lib{s}{s}", .{ name, ext }); |
| 584 | // Look in each directory for a dylib (next, tbd), and then for archive | | |
| 585 | // TODO implement alternative: -search_dylibs_first | | |
| 586 | const exts = switch (lib_kind) { | | |
| 587 | .lib => &[_]?[]const u8{ "dylib", "tbd", "a" }, | | |
| 588 | .framework => &[_]?[]const u8{ null, "dylib", "tbd" }, | | |
| 589 | }; | | |
| 590 | | | |
| 591 | for (exts) |ext| { | | |
| 592 | const lib_name_ext = if (ext) |some| | | |
| 593 | try std.fmt.allocPrint(arena, "{s}.{s}", .{ lib_name, some }) | | |
| 594 | else | | |
| 595 | lib_name; | | |
| 596 | const with_prefix = blk: { | | |
| 597 | switch (lib_kind) { | | |
| 598 | .lib => { | | |
| 599 | break :blk try std.fmt.allocPrint(arena, "lib{s}", .{lib_name_ext}); | | |
| 600 | }, | | |
| 601 | .framework => { | | |
| 602 | const prefix = try std.fmt.allocPrint(arena, "{s}.framework", .{lib_name}); | | |
| 603 | break :blk try fs.path.join(arena, &[_][]const u8{ prefix, lib_name_ext }); | | |
| 604 | }, | | |
| 605 | } | | |
| 606 | }; | | |
| 607 | | 554 | |
| 608 | for (lib_dirs) |dir| { | 555 | for (search_dirs) |dir| { |
| 609 | const full_path = try fs.path.join(arena, &[_][]const u8{ dir, with_prefix }); | 556 | const full_path = try fs.path.join(arena, &[_][]const u8{ dir, search_name }); |
| 610 | | 557 | |
| 611 | // Check if the lib file exists. | 558 | // Check if the file exists. |
| 612 | const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { | 559 | const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { |
| 613 | error.FileNotFound => continue, | 560 | error.FileNotFound => continue, |
| 614 | else => |e| return e, | 561 | else => |e| return e, |
| 615 | }; | 562 | }; |
| 616 | defer tmp.close(); | 563 | defer tmp.close(); |
| 617 | | 564 | |
| 618 | return full_path; | 565 | return full_path; |
| 619 | } | | |
| 620 | } | 566 | } |
| 621 | | 567 | |
| 622 | return null; | 568 | return null; |
| 623 | } | 569 | } |
| 624 | | 570 | |
| 625 | fn resolveLibs( | 571 | fn resolveFramework( |
| 626 | arena: *Allocator, | 572 | arena: *Allocator, |
| 627 | resolved_libs: *std.ArrayList([]const u8), | 573 | search_dirs: []const []const u8, |
| 628 | lib_dirs: []const []const u8, | 574 | name: []const u8, |
| 629 | lib_names: []const []const u8, | 575 | ext: []const u8, |
| 630 | lib_kind: LibKind, | 576 | ) !?[]const u8 { |
| 631 | ) !void { | 577 | const search_name = try std.fmt.allocPrint(arena, "{s}{s}", .{ name, ext }); |
| 632 | for (lib_names) |lib_name| { | 578 | const prefix_path = try std.fmt.allocPrint(arena, "{s}.framework", .{name}); |
| 633 | if (try resolveLib(arena, lib_dirs, lib_name, lib_kind)) |full_path| { | 579 | |
| 634 | try resolved_libs.append(full_path); | 580 | for (search_dirs) |dir| { |
| 635 | } else { | 581 | const full_path = try fs.path.join(arena, &[_][]const u8{ dir, prefix_path, search_name }); |
| 636 | switch (lib_kind) { | 582 | |
| 637 | .lib => { | 583 | // Check if the file exists. |
| 638 | log.warn("library not found for '-l{s}'", .{lib_name}); | 584 | const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { |
| 639 | log.warn("Library search paths:", .{}); | 585 | error.FileNotFound => continue, |
| 640 | }, | 586 | else => |e| return e, |
| 641 | .framework => { | 587 | }; |
| 642 | log.warn("framework not found for '-f{s}'", .{lib_name}); | 588 | defer tmp.close(); |
| 643 | log.warn("Framework search paths:", .{}); | 589 | |
| 644 | }, | 590 | return full_path; |
| 645 | } | | |
| 646 | for (lib_dirs) |dir| { | | |
| 647 | log.warn(" {s}", .{dir}); | | |
| 648 | } | | |
| 649 | } | | |
| 650 | } | 591 | } |
| | 592 | |
| | 593 | return null; |
| 651 | } | 594 | } |
| 652 | | 595 | |
| 653 | fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | 596 | fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| ... | @@ -852,56 +795,96 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -852,56 +795,96 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 852 | } | 795 | } |
| 853 | | 796 | |
| 854 | var lib_dirs = std.ArrayList([]const u8).init(arena); | 797 | var lib_dirs = std.ArrayList([]const u8).init(arena); |
| 855 | try resolveDirs( | 798 | for (self.base.options.lib_dirs) |dir| { |
| 856 | arena, | 799 | if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| { |
| 857 | &lib_dirs, | 800 | try lib_dirs.append(search_dir); |
| 858 | self.base.options.sysroot, | 801 | } else { |
| 859 | self.base.options.lib_dirs, | 802 | log.warn("directory not found for '-L{s}'", .{dir}); |
| 860 | .lib, | 803 | } |
| 861 | ); | 804 | } |
| 862 | | 805 | |
| 863 | var libs = std.ArrayList([]const u8).init(arena); | 806 | var libs = std.ArrayList([]const u8).init(arena); |
| 864 | try resolveLibs( | 807 | var lib_not_found = false; |
| 865 | arena, | 808 | for (search_lib_names.items) |lib_name| { |
| 866 | &libs, | 809 | // Assume ld64 default: -search_paths_first |
| 867 | lib_dirs.items, | 810 | // Look in each directory for a dylib (stub first), and then for archive |
| 868 | search_lib_names.items, | 811 | // TODO implement alternative: -search_dylibs_first |
| 869 | .lib, | 812 | for (&[_][]const u8{ ".tbd", ".dylib", ".a" }) |ext| { |
| 870 | ); | 813 | if (try resolveLib(arena, lib_dirs.items, lib_name, ext)) |full_path| { |
| | 814 | try libs.append(full_path); |
| | 815 | break; |
| | 816 | } |
| | 817 | } else { |
| | 818 | log.warn("library not found for '-l{s}'", .{lib_name}); |
| | 819 | lib_not_found = true; |
| | 820 | } |
| | 821 | } |
| | 822 | |
| | 823 | if (lib_not_found) { |
| | 824 | log.warn("Library search paths:", .{}); |
| | 825 | for (lib_dirs.items) |dir| { |
| | 826 | log.warn(" {s}", .{dir}); |
| | 827 | } |
| | 828 | } |
| 871 | | 829 | |
| 872 | // If we're compiling native and we can find libSystem.B.{dylib, tbd}, | 830 | // If we're compiling native and we can find libSystem.B.{dylib, tbd}, |
| 873 | // we link against that instead of embedded libSystem.B.tbd file. | 831 | // we link against that instead of embedded libSystem.B.tbd file. |
| 874 | var link_native_libsystem = false; | 832 | var native_libsystem_available = false; |
| 875 | if (self.base.options.is_native_os) { | 833 | if (self.base.options.is_native_os) blk: { |
| 876 | if (try resolveLib(arena, lib_dirs.items, "System", .lib)) |full_path| { | 834 | // Try stub file first. If we hit it, then we're done as the stub file |
| | 835 | // re-exports every single symbol definition. |
| | 836 | if (try resolveLib(arena, lib_dirs.items, "System", ".tbd")) |full_path| { |
| 877 | try libs.append(full_path); | 837 | try libs.append(full_path); |
| 878 | link_native_libsystem = true; | 838 | native_libsystem_available = true; |
| | 839 | break :blk; |
| | 840 | } |
| | 841 | // If we didn't hit the stub file, try .dylib next. However, libSystem.dylib |
| | 842 | // doesn't export libc.dylib which we'll need to resolve subsequently also. |
| | 843 | if (try resolveLib(arena, lib_dirs.items, "System", ".dylib")) |libsystem_path| { |
| | 844 | if (try resolveLib(arena, lib_dirs.items, "c", ".dylib")) |libc_path| { |
| | 845 | try libs.append(libsystem_path); |
| | 846 | try libs.append(libc_path); |
| | 847 | native_libsystem_available = true; |
| | 848 | break :blk; |
| | 849 | } |
| 879 | } | 850 | } |
| 880 | } | 851 | } |
| 881 | if (!link_native_libsystem) { | 852 | if (!native_libsystem_available) { |
| 882 | const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ | 853 | const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ |
| 883 | "libc", "darwin", "libSystem.B.tbd", | 854 | "libc", "darwin", "libSystem.B.tbd", |
| 884 | }); | 855 | }); |
| 885 | try positionals.append(full_path); | 856 | try libs.append(full_path); |
| 886 | } | 857 | } |
| 887 | | 858 | |
| 888 | // frameworks | 859 | // frameworks |
| 889 | var framework_dirs = std.ArrayList([]const u8).init(arena); | 860 | var framework_dirs = std.ArrayList([]const u8).init(arena); |
| 890 | try resolveDirs( | 861 | for (self.base.options.framework_dirs) |dir| { |
| 891 | arena, | 862 | if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| { |
| 892 | &framework_dirs, | 863 | try framework_dirs.append(search_dir); |
| 893 | self.base.options.sysroot, | 864 | } else { |
| 894 | self.base.options.framework_dirs, | 865 | log.warn("directory not found for '-F{s}'", .{dir}); |
| 895 | .framework, | 866 | } |
| 896 | ); | 867 | } |
| 897 | | 868 | |
| 898 | try resolveLibs( | 869 | var framework_not_found = false; |
| 899 | arena, | 870 | for (self.base.options.frameworks) |framework| { |
| 900 | &libs, | 871 | for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| { |
| 901 | framework_dirs.items, | 872 | if (try resolveFramework(arena, framework_dirs.items, framework, ext)) |full_path| { |
| 902 | self.base.options.frameworks, | 873 | try libs.append(full_path); |
| 903 | .framework, | 874 | break; |
| 904 | ); | 875 | } |
| | 876 | } else { |
| | 877 | log.warn("framework not found for '-f{s}'", .{framework}); |
| | 878 | framework_not_found = true; |
| | 879 | } |
| | 880 | } |
| | 881 | |
| | 882 | if (framework_not_found) { |
| | 883 | log.warn("Framework search paths:", .{}); |
| | 884 | for (framework_dirs.items) |dir| { |
| | 885 | log.warn(" {s}", .{dir}); |
| | 886 | } |
| | 887 | } |
| 905 | | 888 | |
| 906 | // rpaths | 889 | // rpaths |
| 907 | var rpath_table = std.StringArrayHashMap(void).init(arena); | 890 | var rpath_table = std.StringArrayHashMap(void).init(arena); |
| ... | @@ -937,8 +920,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -937,8 +920,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 937 | try argv.append("-o"); | 920 | try argv.append("-o"); |
| 938 | try argv.append(full_out_path); | 921 | try argv.append(full_out_path); |
| 939 | | 922 | |
| 940 | if (link_native_libsystem) { | 923 | if (native_libsystem_available) { |
| 941 | try argv.append("-lSystem"); | 924 | try argv.append("-lSystem"); |
| | 925 | try argv.append("-lc"); |
| 942 | } | 926 | } |
| 943 | | 927 | |
| 944 | for (search_lib_names.items) |l_name| { | 928 | for (search_lib_names.items) |l_name| { |