| ... | @@ -514,6 +514,119 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -514,6 +514,119 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 514 | } | 514 | } |
| 515 | } | 515 | } |
| 516 | | 516 | |
| | 517 | fn resolvePaths( |
| | 518 | arena: *Allocator, |
| | 519 | resolved_paths: *std.ArrayList([]const u8), |
| | 520 | syslibroot: ?[]const u8, |
| | 521 | search_dirs: []const []const u8, |
| | 522 | lib_names: []const []const u8, |
| | 523 | kind: enum { lib, framework }, |
| | 524 | ) !void { |
| | 525 | var resolved_dirs = std.ArrayList([]const u8).init(arena); |
| | 526 | for (search_dirs) |dir| { |
| | 527 | if (fs.path.isAbsolute(dir)) { |
| | 528 | var candidates = std.ArrayList([]const u8).init(arena); |
| | 529 | if (syslibroot) |root| { |
| | 530 | const full_path = try fs.path.join(arena, &[_][]const u8{ root, dir }); |
| | 531 | try candidates.append(full_path); |
| | 532 | } |
| | 533 | try candidates.append(dir); |
| | 534 | |
| | 535 | var found = false; |
| | 536 | for (candidates.items) |candidate| { |
| | 537 | // Verify that search path actually exists |
| | 538 | var tmp = fs.cwd().openDir(candidate, .{}) catch |err| switch (err) { |
| | 539 | error.FileNotFound => continue, |
| | 540 | else => |e| return e, |
| | 541 | }; |
| | 542 | defer tmp.close(); |
| | 543 | |
| | 544 | try resolved_dirs.append(candidate); |
| | 545 | found = true; |
| | 546 | break; |
| | 547 | } |
| | 548 | |
| | 549 | if (!found) { |
| | 550 | switch (kind) { |
| | 551 | .lib => log.warn("directory not found for '-L{s}'", .{dir}), |
| | 552 | .framework => log.warn("directory not found for '-F{s}'", .{dir}), |
| | 553 | } |
| | 554 | } |
| | 555 | } else { |
| | 556 | // Verify that search path actually exists |
| | 557 | var tmp = fs.cwd().openDir(dir, .{}) catch |err| switch (err) { |
| | 558 | error.FileNotFound => { |
| | 559 | switch (kind) { |
| | 560 | .lib => log.warn("directory not found for '-L{s}'", .{dir}), |
| | 561 | .framework => log.warn("directory not found for '-F{s}'", .{dir}), |
| | 562 | } |
| | 563 | continue; |
| | 564 | }, |
| | 565 | else => |e| return e, |
| | 566 | }; |
| | 567 | defer tmp.close(); |
| | 568 | |
| | 569 | try resolved_dirs.append(dir); |
| | 570 | } |
| | 571 | } |
| | 572 | |
| | 573 | // Assume ld64 default: -search_paths_first |
| | 574 | // Look in each directory for a dylib (next, tbd), and then for archive |
| | 575 | // TODO implement alternative: -search_dylibs_first |
| | 576 | const exts = switch (kind) { |
| | 577 | .lib => &[_][]const u8{ "dylib", "tbd", "a" }, |
| | 578 | .framework => &[_][]const u8{ "dylib", "tbd" }, |
| | 579 | }; |
| | 580 | |
| | 581 | for (lib_names) |lib_name| { |
| | 582 | var found = false; |
| | 583 | |
| | 584 | ext: for (exts) |ext| { |
| | 585 | const lib_name_ext = blk: { |
| | 586 | switch (kind) { |
| | 587 | .lib => break :blk try std.fmt.allocPrint(arena, "lib{s}.{s}", .{ lib_name, ext }), |
| | 588 | .framework => { |
| | 589 | const prefix = try std.fmt.allocPrint(arena, "{s}.framework", .{lib_name}); |
| | 590 | const nn = try std.fmt.allocPrint(arena, "{s}.{s}", .{ lib_name, ext }); |
| | 591 | break :blk try fs.path.join(arena, &[_][]const u8{ prefix, nn }); |
| | 592 | }, |
| | 593 | } |
| | 594 | }; |
| | 595 | |
| | 596 | for (resolved_dirs.items) |dir| { |
| | 597 | const full_path = try fs.path.join(arena, &[_][]const u8{ dir, lib_name_ext }); |
| | 598 | |
| | 599 | // Check if the lib file exists. |
| | 600 | const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { |
| | 601 | error.FileNotFound => continue, |
| | 602 | else => |e| return e, |
| | 603 | }; |
| | 604 | defer tmp.close(); |
| | 605 | |
| | 606 | try resolved_paths.append(full_path); |
| | 607 | found = true; |
| | 608 | break :ext; |
| | 609 | } |
| | 610 | } |
| | 611 | |
| | 612 | if (!found) { |
| | 613 | switch (kind) { |
| | 614 | .lib => { |
| | 615 | log.warn("library not found for '-l{s}'", .{lib_name}); |
| | 616 | log.warn("Library search paths:", .{}); |
| | 617 | }, |
| | 618 | .framework => { |
| | 619 | log.warn("framework not found for '-f{s}'", .{lib_name}); |
| | 620 | log.warn("Framework search paths:", .{}); |
| | 621 | }, |
| | 622 | } |
| | 623 | for (resolved_dirs.items) |dir| { |
| | 624 | log.warn(" {s}", .{dir}); |
| | 625 | } |
| | 626 | } |
| | 627 | } |
| | 628 | } |
| | 629 | |
| 517 | fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | 630 | fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 518 | const tracy = trace(@src()); | 631 | const tracy = trace(@src()); |
| 519 | defer tracy.end(); | 632 | defer tracy.end(); |
| ... | @@ -700,7 +813,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -700,7 +813,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 700 | } | 813 | } |
| 701 | | 814 | |
| 702 | // Shared and static libraries passed via `-l` flag. | 815 | // Shared and static libraries passed via `-l` flag. |
| 703 | var libs = std.ArrayList([]const u8).init(arena); | | |
| 704 | var search_lib_names = std.ArrayList([]const u8).init(arena); | 816 | var search_lib_names = std.ArrayList([]const u8).init(arena); |
| 705 | | 817 | |
| 706 | const system_libs = self.base.options.system_libs.keys(); | 818 | const system_libs = self.base.options.system_libs.keys(); |
| ... | @@ -716,84 +828,15 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -716,84 +828,15 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 716 | try search_lib_names.append(link_lib); | 828 | try search_lib_names.append(link_lib); |
| 717 | } | 829 | } |
| 718 | | 830 | |
| 719 | var search_lib_dirs = std.ArrayList([]const u8).init(arena); | 831 | var libs = std.ArrayList([]const u8).init(arena); |
| 720 | | 832 | try resolvePaths( |
| 721 | for (self.base.options.lib_dirs) |path| { | 833 | arena, |
| 722 | if (fs.path.isAbsolute(path)) { | 834 | &libs, |
| 723 | var candidates = std.ArrayList([]const u8).init(arena); | 835 | self.base.options.syslibroot, |
| 724 | if (self.base.options.syslibroot) |syslibroot| { | 836 | self.base.options.lib_dirs, |
| 725 | const full_path = try fs.path.join(arena, &[_][]const u8{ syslibroot, path }); | 837 | search_lib_names.items, |
| 726 | try candidates.append(full_path); | 838 | .lib, |
| 727 | } | 839 | ); |
| 728 | try candidates.append(path); | | |
| 729 | | | |
| 730 | var found = false; | | |
| 731 | for (candidates.items) |candidate| { | | |
| 732 | // Verify that search path actually exists | | |
| 733 | var tmp = fs.cwd().openDir(candidate, .{}) catch |err| switch (err) { | | |
| 734 | error.FileNotFound => continue, | | |
| 735 | else => |e| return e, | | |
| 736 | }; | | |
| 737 | defer tmp.close(); | | |
| 738 | | | |
| 739 | try search_lib_dirs.append(candidate); | | |
| 740 | found = true; | | |
| 741 | break; | | |
| 742 | } | | |
| 743 | | | |
| 744 | if (!found) { | | |
| 745 | log.warn("directory not found for '-L{s}'", .{path}); | | |
| 746 | } | | |
| 747 | } else { | | |
| 748 | // Verify that search path actually exists | | |
| 749 | var tmp = fs.cwd().openDir(path, .{}) catch |err| switch (err) { | | |
| 750 | error.FileNotFound => { | | |
| 751 | log.warn("directory not found for '-L{s}'", .{path}); | | |
| 752 | continue; | | |
| 753 | }, | | |
| 754 | else => |e| return e, | | |
| 755 | }; | | |
| 756 | defer tmp.close(); | | |
| 757 | | | |
| 758 | try search_lib_dirs.append(path); | | |
| 759 | } | | |
| 760 | } | | |
| 761 | | | |
| 762 | // Assume ld64 default: -search_paths_first | | |
| 763 | // Look in each directory for a dylib (next, tbd), and then for archive | | |
| 764 | // TODO implement alternative: -search_dylibs_first | | |
| 765 | const exts = &[_][]const u8{ "dylib", "tbd", "a" }; | | |
| 766 | | | |
| 767 | for (search_lib_names.items) |l_name| { | | |
| 768 | var found = false; | | |
| 769 | | | |
| 770 | ext: for (exts) |ext| { | | |
| 771 | const l_name_ext = try std.fmt.allocPrint(arena, "lib{s}.{s}", .{ l_name, ext }); | | |
| 772 | | | |
| 773 | for (search_lib_dirs.items) |lib_dir| { | | |
| 774 | const full_path = try fs.path.join(arena, &[_][]const u8{ lib_dir, l_name_ext }); | | |
| 775 | | | |
| 776 | // Check if the lib file exists. | | |
| 777 | const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { | | |
| 778 | error.FileNotFound => continue, | | |
| 779 | else => |e| return e, | | |
| 780 | }; | | |
| 781 | defer tmp.close(); | | |
| 782 | | | |
| 783 | try libs.append(full_path); | | |
| 784 | found = true; | | |
| 785 | break :ext; | | |
| 786 | } | | |
| 787 | } | | |
| 788 | | | |
| 789 | if (!found) { | | |
| 790 | log.warn("library not found for '-l{s}'", .{l_name}); | | |
| 791 | log.warn("Library search paths:", .{}); | | |
| 792 | for (search_lib_dirs.items) |lib_dir| { | | |
| 793 | log.warn(" {s}", .{lib_dir}); | | |
| 794 | } | | |
| 795 | } | | |
| 796 | } | | |
| 797 | | 840 | |
| 798 | // rpaths | 841 | // rpaths |
| 799 | var rpath_table = std.StringArrayHashMap(void).init(arena); | 842 | var rpath_table = std.StringArrayHashMap(void).init(arena); |
| ... | @@ -809,9 +852,14 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -809,9 +852,14 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 809 | } | 852 | } |
| 810 | | 853 | |
| 811 | // frameworks | 854 | // frameworks |
| 812 | for (self.base.options.frameworks) |framework| { | 855 | try resolvePaths( |
| 813 | log.warn("frameworks not yet supported for '-framework {s}'", .{framework}); | 856 | arena, |
| 814 | } | 857 | &libs, |
| | 858 | self.base.options.syslibroot, |
| | 859 | self.base.options.framework_dirs, |
| | 860 | self.base.options.frameworks, |
| | 861 | .framework, |
| | 862 | ); |
| 815 | | 863 | |
| 816 | if (self.base.options.verbose_link) { | 864 | if (self.base.options.verbose_link) { |
| 817 | var argv = std.ArrayList([]const u8).init(arena); | 865 | var argv = std.ArrayList([]const u8).init(arena); |