| ... | ... | @@ -514,140 +514,83 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 514 | 514 | } |
| 515 | 515 | } |
| 516 | 516 | |
| 517 | | const LibKind = enum { |
| 518 | | lib, |
| 519 | | framework, |
| 520 | | }; |
| 521 | | |
| 522 | | fn resolveDirs( |
| 517 | fn resolveSearchDir( |
| 523 | 518 | arena: *Allocator, |
| 524 | | resolved_dirs: *std.ArrayList([]const u8), |
| 519 | dir: []const u8, |
| 525 | 520 | syslibroot: ?[]const u8, |
| 526 | | search_dirs: []const []const u8, |
| 527 | | lib_kind: LibKind, |
| 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(); |
| 521 | ) !?[]const u8 { |
| 522 | var candidates = std.ArrayList([]const u8).init(arena); |
| 546 | 523 | |
| 547 | | try resolved_dirs.append(candidate); |
| 548 | | found = true; |
| 549 | | break; |
| 550 | | } |
| 524 | if (fs.path.isAbsolute(dir)) { |
| 525 | if (syslibroot) |root| { |
| 526 | const full_path = try fs.path.join(arena, &[_][]const u8{ root, dir }); |
| 527 | try candidates.append(full_path); |
| 528 | } |
| 529 | } |
| 551 | 530 | |
| 552 | | if (!found) { |
| 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(); |
| 531 | try candidates.append(dir); |
| 571 | 532 | |
| 572 | | try resolved_dirs.append(dir); |
| 573 | | } |
| 533 | for (candidates.items) |candidate| { |
| 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 | 547 | fn resolveLib( |
| 578 | 548 | arena: *Allocator, |
| 579 | | lib_dirs: []const []const u8, |
| 580 | | lib_name: []const u8, |
| 581 | | lib_kind: LibKind, |
| 549 | search_dirs: []const []const u8, |
| 550 | name: []const u8, |
| 551 | ext: []const u8, |
| 582 | 552 | ) !?[]const u8 { |
| 583 | | // Assume ld64 default: -search_paths_first |
| 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 | | }; |
| 553 | const search_name = try std.fmt.allocPrint(arena, "lib{s}{s}", .{ name, ext }); |
| 607 | 554 | |
| 608 | | for (lib_dirs) |dir| { |
| 609 | | const full_path = try fs.path.join(arena, &[_][]const u8{ dir, with_prefix }); |
| 555 | for (search_dirs) |dir| { |
| 556 | const full_path = try fs.path.join(arena, &[_][]const u8{ dir, search_name }); |
| 610 | 557 | |
| 611 | | // Check if the lib file exists. |
| 612 | | const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { |
| 613 | | error.FileNotFound => continue, |
| 614 | | else => |e| return e, |
| 615 | | }; |
| 616 | | defer tmp.close(); |
| 558 | // Check if the file exists. |
| 559 | const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { |
| 560 | error.FileNotFound => continue, |
| 561 | else => |e| return e, |
| 562 | }; |
| 563 | defer tmp.close(); |
| 617 | 564 | |
| 618 | | return full_path; |
| 619 | | } |
| 565 | return full_path; |
| 620 | 566 | } |
| 621 | 567 | |
| 622 | 568 | return null; |
| 623 | 569 | } |
| 624 | 570 | |
| 625 | | fn resolveLibs( |
| 571 | fn resolveFramework( |
| 626 | 572 | arena: *Allocator, |
| 627 | | resolved_libs: *std.ArrayList([]const u8), |
| 628 | | lib_dirs: []const []const u8, |
| 629 | | lib_names: []const []const u8, |
| 630 | | lib_kind: LibKind, |
| 631 | | ) !void { |
| 632 | | for (lib_names) |lib_name| { |
| 633 | | if (try resolveLib(arena, lib_dirs, lib_name, lib_kind)) |full_path| { |
| 634 | | try resolved_libs.append(full_path); |
| 635 | | } else { |
| 636 | | switch (lib_kind) { |
| 637 | | .lib => { |
| 638 | | log.warn("library not found for '-l{s}'", .{lib_name}); |
| 639 | | log.warn("Library search paths:", .{}); |
| 640 | | }, |
| 641 | | .framework => { |
| 642 | | log.warn("framework not found for '-f{s}'", .{lib_name}); |
| 643 | | log.warn("Framework search paths:", .{}); |
| 644 | | }, |
| 645 | | } |
| 646 | | for (lib_dirs) |dir| { |
| 647 | | log.warn(" {s}", .{dir}); |
| 648 | | } |
| 649 | | } |
| 573 | search_dirs: []const []const u8, |
| 574 | name: []const u8, |
| 575 | ext: []const u8, |
| 576 | ) !?[]const u8 { |
| 577 | const search_name = try std.fmt.allocPrint(arena, "{s}{s}", .{ name, ext }); |
| 578 | const prefix_path = try std.fmt.allocPrint(arena, "{s}.framework", .{name}); |
| 579 | |
| 580 | for (search_dirs) |dir| { |
| 581 | const full_path = try fs.path.join(arena, &[_][]const u8{ dir, prefix_path, search_name }); |
| 582 | |
| 583 | // Check if the file exists. |
| 584 | const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { |
| 585 | error.FileNotFound => continue, |
| 586 | else => |e| return e, |
| 587 | }; |
| 588 | defer tmp.close(); |
| 589 | |
| 590 | return full_path; |
| 650 | 591 | } |
| 592 | |
| 593 | return null; |
| 651 | 594 | } |
| 652 | 595 | |
| 653 | 596 | fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| ... | ... | @@ -852,56 +795,96 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 852 | 795 | } |
| 853 | 796 | |
| 854 | 797 | var lib_dirs = std.ArrayList([]const u8).init(arena); |
| 855 | | try resolveDirs( |
| 856 | | arena, |
| 857 | | &lib_dirs, |
| 858 | | self.base.options.sysroot, |
| 859 | | self.base.options.lib_dirs, |
| 860 | | .lib, |
| 861 | | ); |
| 798 | for (self.base.options.lib_dirs) |dir| { |
| 799 | if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| { |
| 800 | try lib_dirs.append(search_dir); |
| 801 | } else { |
| 802 | log.warn("directory not found for '-L{s}'", .{dir}); |
| 803 | } |
| 804 | } |
| 862 | 805 | |
| 863 | 806 | var libs = std.ArrayList([]const u8).init(arena); |
| 864 | | try resolveLibs( |
| 865 | | arena, |
| 866 | | &libs, |
| 867 | | lib_dirs.items, |
| 868 | | search_lib_names.items, |
| 869 | | .lib, |
| 870 | | ); |
| 807 | var lib_not_found = false; |
| 808 | for (search_lib_names.items) |lib_name| { |
| 809 | // Assume ld64 default: -search_paths_first |
| 810 | // Look in each directory for a dylib (stub first), and then for archive |
| 811 | // TODO implement alternative: -search_dylibs_first |
| 812 | for (&[_][]const u8{ ".tbd", ".dylib", ".a" }) |ext| { |
| 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 | 830 | // If we're compiling native and we can find libSystem.B.{dylib, tbd}, |
| 873 | 831 | // we link against that instead of embedded libSystem.B.tbd file. |
| 874 | | var link_native_libsystem = false; |
| 875 | | if (self.base.options.is_native_os) { |
| 876 | | if (try resolveLib(arena, lib_dirs.items, "System", .lib)) |full_path| { |
| 832 | var native_libsystem_available = false; |
| 833 | if (self.base.options.is_native_os) blk: { |
| 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 | 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 | 853 | const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ |
| 883 | 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 | 859 | // frameworks |
| 889 | 860 | var framework_dirs = std.ArrayList([]const u8).init(arena); |
| 890 | | try resolveDirs( |
| 891 | | arena, |
| 892 | | &framework_dirs, |
| 893 | | self.base.options.sysroot, |
| 894 | | self.base.options.framework_dirs, |
| 895 | | .framework, |
| 896 | | ); |
| 861 | for (self.base.options.framework_dirs) |dir| { |
| 862 | if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| { |
| 863 | try framework_dirs.append(search_dir); |
| 864 | } else { |
| 865 | log.warn("directory not found for '-F{s}'", .{dir}); |
| 866 | } |
| 867 | } |
| 897 | 868 | |
| 898 | | try resolveLibs( |
| 899 | | arena, |
| 900 | | &libs, |
| 901 | | framework_dirs.items, |
| 902 | | self.base.options.frameworks, |
| 903 | | .framework, |
| 904 | | ); |
| 869 | var framework_not_found = false; |
| 870 | for (self.base.options.frameworks) |framework| { |
| 871 | for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| { |
| 872 | if (try resolveFramework(arena, framework_dirs.items, framework, ext)) |full_path| { |
| 873 | try libs.append(full_path); |
| 874 | break; |
| 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 | 889 | // rpaths |
| 907 | 890 | var rpath_table = std.StringArrayHashMap(void).init(arena); |
| ... | ... | @@ -937,8 +920,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 937 | 920 | try argv.append("-o"); |
| 938 | 921 | try argv.append(full_out_path); |
| 939 | 922 | |
| 940 | | if (link_native_libsystem) { |
| 923 | if (native_libsystem_available) { |
| 941 | 924 | try argv.append("-lSystem"); |
| 925 | try argv.append("-lc"); |
| 942 | 926 | } |
| 943 | 927 | |
| 944 | 928 | for (search_lib_names.items) |l_name| { |