| ... | ... | @@ -3618,6 +3618,28 @@ fn buildOutputType( |
| 3618 | 3618 | return cleanExit(); |
| 3619 | 3619 | } |
| 3620 | 3620 | |
| 3621 | const LinkerInput = union(enum) { |
| 3622 | /// An argument like: -l[name] |
| 3623 | named: Named, |
| 3624 | /// When a file path is provided. |
| 3625 | path: struct { |
| 3626 | path: Path, |
| 3627 | /// We still need all this info because the path may point to a .so |
| 3628 | /// file which may actually be a "linker script" that references |
| 3629 | /// library names which need to be resolved. |
| 3630 | info: SystemLib, |
| 3631 | }, |
| 3632 | /// Put exactly this string in the dynamic section, no rpath. |
| 3633 | exact: struct { |
| 3634 | name: []const u8, |
| 3635 | }, |
| 3636 | |
| 3637 | const Named = struct { |
| 3638 | name: []const u8, |
| 3639 | info: SystemLib, |
| 3640 | }; |
| 3641 | }; |
| 3642 | |
| 3621 | 3643 | const CreateModule = struct { |
| 3622 | 3644 | global_cache_directory: Cache.Directory, |
| 3623 | 3645 | modules: std.StringArrayHashMapUnmanaged(CliModule), |
| ... | ... | @@ -3760,10 +3782,7 @@ fn createModule( |
| 3760 | 3782 | // First, remove libc, libc++, and compiler_rt libraries from the system libraries list. |
| 3761 | 3783 | // We need to know whether the set of system libraries contains anything besides these |
| 3762 | 3784 | // to decide whether to trigger native path detection logic. |
| 3763 | | var external_system_libs: std.MultiArrayList(struct { |
| 3764 | | name: []const u8, |
| 3765 | | info: SystemLib, |
| 3766 | | }) = .{}; |
| 3785 | var external_linker_inputs: std.ArrayListUnmanaged(LinkerInput) = .empty; |
| 3767 | 3786 | for (create_module.system_libs.keys(), create_module.system_libs.values()) |lib_name, info| { |
| 3768 | 3787 | if (std.zig.target.isLibCLibName(target, lib_name)) { |
| 3769 | 3788 | create_module.opts.link_libc = true; |
| ... | ... | @@ -3815,13 +3834,13 @@ fn createModule( |
| 3815 | 3834 | } |
| 3816 | 3835 | } |
| 3817 | 3836 | |
| 3818 | | try external_system_libs.append(arena, .{ |
| 3837 | try external_linker_inputs.append(arena, .{ .named = .{ |
| 3819 | 3838 | .name = lib_name, |
| 3820 | 3839 | .info = info, |
| 3821 | | }); |
| 3840 | } }); |
| 3822 | 3841 | } |
| 3823 | | // After this point, external_system_libs is used instead of system_libs. |
| 3824 | | if (external_system_libs.len != 0) |
| 3842 | // After this point, external_linker_inputs is used instead of system_libs. |
| 3843 | if (external_linker_inputs.items.len != 0) |
| 3825 | 3844 | create_module.want_native_include_dirs = true; |
| 3826 | 3845 | |
| 3827 | 3846 | // Resolve the library path arguments with respect to sysroot. |
| ... | ... | @@ -3878,7 +3897,7 @@ fn createModule( |
| 3878 | 3897 | } |
| 3879 | 3898 | |
| 3880 | 3899 | if (builtin.target.os.tag == .windows and (target.abi == .msvc or target.abi == .itanium) and |
| 3881 | | external_system_libs.len != 0) |
| 3900 | external_linker_inputs.items.len != 0) |
| 3882 | 3901 | { |
| 3883 | 3902 | if (create_module.libc_installation == null) { |
| 3884 | 3903 | create_module.libc_installation = LibCInstallation.findNative(.{ |
| ... | ... | @@ -3899,20 +3918,67 @@ fn createModule( |
| 3899 | 3918 | // If any libs in this list are statically provided, we omit them from the |
| 3900 | 3919 | // resolved list and populate the link_objects array instead. |
| 3901 | 3920 | { |
| 3902 | | var test_path = std.ArrayList(u8).init(gpa); |
| 3903 | | defer test_path.deinit(); |
| 3921 | var test_path: std.ArrayListUnmanaged(u8) = .empty; |
| 3922 | defer test_path.deinit(gpa); |
| 3923 | |
| 3924 | var checked_paths: std.ArrayListUnmanaged(u8) = .empty; |
| 3925 | defer checked_paths.deinit(gpa); |
| 3904 | 3926 | |
| 3905 | | var checked_paths = std.ArrayList(u8).init(gpa); |
| 3906 | | defer checked_paths.deinit(); |
| 3927 | var ld_script_bytes: std.ArrayListUnmanaged(u8) = .empty; |
| 3928 | defer ld_script_bytes.deinit(gpa); |
| 3907 | 3929 | |
| 3908 | | var failed_libs = std.ArrayList(struct { |
| 3930 | var failed_libs: std.ArrayListUnmanaged(struct { |
| 3909 | 3931 | name: []const u8, |
| 3910 | 3932 | strategy: SystemLib.SearchStrategy, |
| 3911 | 3933 | checked_paths: []const u8, |
| 3912 | 3934 | preferred_mode: std.builtin.LinkMode, |
| 3913 | | }).init(arena); |
| 3935 | }) = .empty; |
| 3936 | |
| 3937 | // Convert external system libs into a stack so that items can be |
| 3938 | // pushed to it. |
| 3939 | // |
| 3940 | // This is necessary because shared objects might turn out to be |
| 3941 | // "linker scripts" that in fact resolve to one or more other |
| 3942 | // external system libs, including parameters such as "needed". |
| 3943 | // |
| 3944 | // Unfortunately, such files need to be detected immediately, so |
| 3945 | // that this library search logic can be applied to them. |
| 3946 | mem.reverse(LinkerInput, external_linker_inputs.items); |
| 3947 | |
| 3948 | syslib: while (external_linker_inputs.popOrNull()) |external_linker_input| { |
| 3949 | const external_system_lib: LinkerInput.Named = switch (external_linker_input) { |
| 3950 | .named => |named| named, |
| 3951 | .path => |p| p: { |
| 3952 | if (fs.path.isAbsolute(p.path.sub_path)) { |
| 3953 | try create_module.link_objects.append(arena, .{ |
| 3954 | .path = p.path, |
| 3955 | .needed = p.info.needed, |
| 3956 | .weak = p.info.weak, |
| 3957 | }); |
| 3958 | continue; |
| 3959 | } |
| 3960 | const lib_name, const link_mode = stripLibPrefixAndSuffix(p.path.sub_path, target); |
| 3961 | break :p .{ |
| 3962 | .name = lib_name, |
| 3963 | .info = .{ |
| 3964 | .needed = p.info.needed, |
| 3965 | .weak = p.info.weak, |
| 3966 | .preferred_mode = link_mode, |
| 3967 | .search_strategy = .no_fallback, |
| 3968 | }, |
| 3969 | }; |
| 3970 | }, |
| 3971 | .exact => |exact| { |
| 3972 | try create_module.link_objects.append(arena, .{ |
| 3973 | .path = Path.initCwd(exact.name), |
| 3974 | .loption = true, |
| 3975 | }); |
| 3976 | continue; |
| 3977 | }, |
| 3978 | }; |
| 3979 | const lib_name = external_system_lib.name; |
| 3980 | const info = external_system_lib.info; |
| 3914 | 3981 | |
| 3915 | | syslib: for (external_system_libs.items(.name), external_system_libs.items(.info)) |lib_name, info| { |
| 3916 | 3982 | // Checked in the first pass above while looking for libc libraries. |
| 3917 | 3983 | assert(!fs.path.isAbsolute(lib_name)); |
| 3918 | 3984 | |
| ... | ... | @@ -3921,33 +3987,26 @@ fn createModule( |
| 3921 | 3987 | switch (info.search_strategy) { |
| 3922 | 3988 | .mode_first, .no_fallback => { |
| 3923 | 3989 | // check for preferred mode |
| 3924 | | for (create_module.lib_dirs.items) |lib_dir_path| { |
| 3925 | | if (try accessLibPath( |
| 3926 | | &test_path, |
| 3927 | | &checked_paths, |
| 3928 | | lib_dir_path, |
| 3929 | | lib_name, |
| 3930 | | target, |
| 3931 | | info.preferred_mode, |
| 3932 | | )) { |
| 3933 | | const path = Path.initCwd(try arena.dupe(u8, test_path.items)); |
| 3934 | | switch (info.preferred_mode) { |
| 3935 | | .static => try create_module.link_objects.append(arena, .{ .path = path }), |
| 3936 | | .dynamic => try create_module.resolved_system_libs.append(arena, .{ |
| 3937 | | .name = lib_name, |
| 3938 | | .lib = .{ |
| 3939 | | .needed = info.needed, |
| 3940 | | .weak = info.weak, |
| 3941 | | .path = path, |
| 3942 | | }, |
| 3943 | | }), |
| 3944 | | } |
| 3945 | | continue :syslib; |
| 3946 | | } |
| 3947 | | } |
| 3990 | for (create_module.lib_dirs.items) |lib_dir_path| switch (try accessLibPath( |
| 3991 | gpa, |
| 3992 | arena, |
| 3993 | &test_path, |
| 3994 | &checked_paths, |
| 3995 | &external_linker_inputs, |
| 3996 | create_module, |
| 3997 | &ld_script_bytes, |
| 3998 | lib_dir_path, |
| 3999 | lib_name, |
| 4000 | target, |
| 4001 | info.preferred_mode, |
| 4002 | info, |
| 4003 | )) { |
| 4004 | .ok => continue :syslib, |
| 4005 | .no_match => {}, |
| 4006 | }; |
| 3948 | 4007 | // check for fallback mode |
| 3949 | 4008 | if (info.search_strategy == .no_fallback) { |
| 3950 | | try failed_libs.append(.{ |
| 4009 | try failed_libs.append(arena, .{ |
| 3951 | 4010 | .name = lib_name, |
| 3952 | 4011 | .strategy = info.search_strategy, |
| 3953 | 4012 | .checked_paths = try arena.dupe(u8, checked_paths.items), |
| ... | ... | @@ -3955,31 +4014,24 @@ fn createModule( |
| 3955 | 4014 | }); |
| 3956 | 4015 | continue :syslib; |
| 3957 | 4016 | } |
| 3958 | | for (create_module.lib_dirs.items) |lib_dir_path| { |
| 3959 | | if (try accessLibPath( |
| 3960 | | &test_path, |
| 3961 | | &checked_paths, |
| 3962 | | lib_dir_path, |
| 3963 | | lib_name, |
| 3964 | | target, |
| 3965 | | info.fallbackMode(), |
| 3966 | | )) { |
| 3967 | | const path = Path.initCwd(try arena.dupe(u8, test_path.items)); |
| 3968 | | switch (info.fallbackMode()) { |
| 3969 | | .static => try create_module.link_objects.append(arena, .{ .path = path }), |
| 3970 | | .dynamic => try create_module.resolved_system_libs.append(arena, .{ |
| 3971 | | .name = lib_name, |
| 3972 | | .lib = .{ |
| 3973 | | .needed = info.needed, |
| 3974 | | .weak = info.weak, |
| 3975 | | .path = path, |
| 3976 | | }, |
| 3977 | | }), |
| 3978 | | } |
| 3979 | | continue :syslib; |
| 3980 | | } |
| 3981 | | } |
| 3982 | | try failed_libs.append(.{ |
| 4017 | for (create_module.lib_dirs.items) |lib_dir_path| switch (try accessLibPath( |
| 4018 | gpa, |
| 4019 | arena, |
| 4020 | &test_path, |
| 4021 | &checked_paths, |
| 4022 | &external_linker_inputs, |
| 4023 | create_module, |
| 4024 | &ld_script_bytes, |
| 4025 | lib_dir_path, |
| 4026 | lib_name, |
| 4027 | target, |
| 4028 | info.fallbackMode(), |
| 4029 | info, |
| 4030 | )) { |
| 4031 | .ok => continue :syslib, |
| 4032 | .no_match => {}, |
| 4033 | }; |
| 4034 | try failed_libs.append(arena, .{ |
| 3983 | 4035 | .name = lib_name, |
| 3984 | 4036 | .strategy = info.search_strategy, |
| 3985 | 4037 | .checked_paths = try arena.dupe(u8, checked_paths.items), |
| ... | ... | @@ -3990,54 +4042,44 @@ fn createModule( |
| 3990 | 4042 | .paths_first => { |
| 3991 | 4043 | for (create_module.lib_dirs.items) |lib_dir_path| { |
| 3992 | 4044 | // check for preferred mode |
| 3993 | | if (try accessLibPath( |
| 4045 | switch (try accessLibPath( |
| 4046 | gpa, |
| 4047 | arena, |
| 3994 | 4048 | &test_path, |
| 3995 | 4049 | &checked_paths, |
| 4050 | &external_linker_inputs, |
| 4051 | create_module, |
| 4052 | &ld_script_bytes, |
| 3996 | 4053 | lib_dir_path, |
| 3997 | 4054 | lib_name, |
| 3998 | 4055 | target, |
| 3999 | 4056 | info.preferred_mode, |
| 4057 | info, |
| 4000 | 4058 | )) { |
| 4001 | | const path = Path.initCwd(try arena.dupe(u8, test_path.items)); |
| 4002 | | switch (info.preferred_mode) { |
| 4003 | | .static => try create_module.link_objects.append(arena, .{ .path = path }), |
| 4004 | | .dynamic => try create_module.resolved_system_libs.append(arena, .{ |
| 4005 | | .name = lib_name, |
| 4006 | | .lib = .{ |
| 4007 | | .needed = info.needed, |
| 4008 | | .weak = info.weak, |
| 4009 | | .path = path, |
| 4010 | | }, |
| 4011 | | }), |
| 4012 | | } |
| 4013 | | continue :syslib; |
| 4059 | .ok => continue :syslib, |
| 4060 | .no_match => {}, |
| 4014 | 4061 | } |
| 4015 | 4062 | |
| 4016 | 4063 | // check for fallback mode |
| 4017 | | if (try accessLibPath( |
| 4064 | switch (try accessLibPath( |
| 4065 | gpa, |
| 4066 | arena, |
| 4018 | 4067 | &test_path, |
| 4019 | 4068 | &checked_paths, |
| 4069 | &external_linker_inputs, |
| 4070 | create_module, |
| 4071 | &ld_script_bytes, |
| 4020 | 4072 | lib_dir_path, |
| 4021 | 4073 | lib_name, |
| 4022 | 4074 | target, |
| 4023 | 4075 | info.fallbackMode(), |
| 4076 | info, |
| 4024 | 4077 | )) { |
| 4025 | | const path = Path.initCwd(try arena.dupe(u8, test_path.items)); |
| 4026 | | switch (info.fallbackMode()) { |
| 4027 | | .static => try create_module.link_objects.append(arena, .{ .path = path }), |
| 4028 | | .dynamic => try create_module.resolved_system_libs.append(arena, .{ |
| 4029 | | .name = lib_name, |
| 4030 | | .lib = .{ |
| 4031 | | .needed = info.needed, |
| 4032 | | .weak = info.weak, |
| 4033 | | .path = path, |
| 4034 | | }, |
| 4035 | | }), |
| 4036 | | } |
| 4037 | | continue :syslib; |
| 4078 | .ok => continue :syslib, |
| 4079 | .no_match => {}, |
| 4038 | 4080 | } |
| 4039 | 4081 | } |
| 4040 | | try failed_libs.append(.{ |
| 4082 | try failed_libs.append(arena, .{ |
| 4041 | 4083 | .name = lib_name, |
| 4042 | 4084 | .strategy = info.search_strategy, |
| 4043 | 4085 | .checked_paths = try arena.dupe(u8, checked_paths.items), |
| ... | ... | @@ -4059,8 +4101,8 @@ fn createModule( |
| 4059 | 4101 | process.exit(1); |
| 4060 | 4102 | } |
| 4061 | 4103 | } |
| 4062 | | // After this point, create_module.resolved_system_libs is used instead of |
| 4063 | | // create_module.external_system_libs. |
| 4104 | // After this point, create_module.resolved_system_libs is used instead |
| 4105 | // of external_linker_inputs. |
| 4064 | 4106 | |
| 4065 | 4107 | if (create_module.resolved_system_libs.len != 0) |
| 4066 | 4108 | create_module.opts.any_dyn_libs = true; |
| ... | ... | @@ -6857,33 +6899,45 @@ const ClangSearchSanitizer = struct { |
| 6857 | 6899 | }; |
| 6858 | 6900 | }; |
| 6859 | 6901 | |
| 6902 | const AccessLibPathResult = enum { ok, no_match }; |
| 6903 | |
| 6860 | 6904 | fn accessLibPath( |
| 6861 | | test_path: *std.ArrayList(u8), |
| 6862 | | checked_paths: *std.ArrayList(u8), |
| 6905 | gpa: Allocator, |
| 6906 | arena: Allocator, |
| 6907 | /// Allocated via `gpa`. |
| 6908 | test_path: *std.ArrayListUnmanaged(u8), |
| 6909 | /// Allocated via `gpa`. |
| 6910 | checked_paths: *std.ArrayListUnmanaged(u8), |
| 6911 | /// Allocated via `arena`. |
| 6912 | external_linker_inputs: *std.ArrayListUnmanaged(LinkerInput), |
| 6913 | create_module: *CreateModule, |
| 6914 | /// Allocated via `gpa`. |
| 6915 | ld_script_bytes: *std.ArrayListUnmanaged(u8), |
| 6863 | 6916 | lib_dir_path: []const u8, |
| 6864 | 6917 | lib_name: []const u8, |
| 6865 | 6918 | target: std.Target, |
| 6866 | 6919 | link_mode: std.builtin.LinkMode, |
| 6867 | | ) !bool { |
| 6920 | parent: SystemLib, |
| 6921 | ) Allocator.Error!AccessLibPathResult { |
| 6868 | 6922 | const sep = fs.path.sep_str; |
| 6869 | 6923 | |
| 6870 | 6924 | if (target.isDarwin() and link_mode == .dynamic) tbd: { |
| 6871 | 6925 | // Prefer .tbd over .dylib. |
| 6872 | 6926 | test_path.clearRetainingCapacity(); |
| 6873 | | try test_path.writer().print("{s}" ++ sep ++ "lib{s}.tbd", .{ lib_dir_path, lib_name }); |
| 6874 | | try checked_paths.writer().print("\n {s}", .{test_path.items}); |
| 6927 | try test_path.writer(gpa).print("{s}" ++ sep ++ "lib{s}.tbd", .{ lib_dir_path, lib_name }); |
| 6928 | try checked_paths.writer(gpa).print("\n {s}", .{test_path.items}); |
| 6875 | 6929 | fs.cwd().access(test_path.items, .{}) catch |err| switch (err) { |
| 6876 | 6930 | error.FileNotFound => break :tbd, |
| 6877 | 6931 | else => |e| fatal("unable to search for tbd library '{s}': {s}", .{ |
| 6878 | 6932 | test_path.items, @errorName(e), |
| 6879 | 6933 | }), |
| 6880 | 6934 | }; |
| 6881 | | return true; |
| 6935 | return finishAccessLibPath(arena, create_module, test_path, link_mode, parent, lib_name); |
| 6882 | 6936 | } |
| 6883 | 6937 | |
| 6884 | 6938 | main_check: { |
| 6885 | 6939 | test_path.clearRetainingCapacity(); |
| 6886 | | try test_path.writer().print("{s}" ++ sep ++ "{s}{s}{s}", .{ |
| 6940 | try test_path.writer(gpa).print("{s}" ++ sep ++ "{s}{s}{s}", .{ |
| 6887 | 6941 | lib_dir_path, |
| 6888 | 6942 | target.libPrefix(), |
| 6889 | 6943 | lib_name, |
| ... | ... | @@ -6892,49 +6946,148 @@ fn accessLibPath( |
| 6892 | 6946 | .dynamic => target.dynamicLibSuffix(), |
| 6893 | 6947 | }, |
| 6894 | 6948 | }); |
| 6895 | | try checked_paths.writer().print("\n {s}", .{test_path.items}); |
| 6949 | try checked_paths.writer(gpa).print("\n {s}", .{test_path.items}); |
| 6950 | |
| 6951 | // In the case of .so files, they might actually be "linker scripts" |
| 6952 | // that contain references to other libraries. |
| 6953 | if (target.ofmt == .elf and mem.endsWith(u8, test_path.items, ".so")) { |
| 6954 | var file = fs.cwd().openFile(test_path.items, .{}) catch |err| switch (err) { |
| 6955 | error.FileNotFound => break :main_check, |
| 6956 | else => |e| fatal("unable to search for {s} library '{s}': {s}", .{ |
| 6957 | @tagName(link_mode), test_path.items, @errorName(e), |
| 6958 | }), |
| 6959 | }; |
| 6960 | defer file.close(); |
| 6961 | try ld_script_bytes.resize(gpa, @sizeOf(std.elf.Elf64_Ehdr)); |
| 6962 | const n = file.readAll(ld_script_bytes.items) catch |err| fatal("failed to read {s}: {s}", .{ |
| 6963 | test_path.items, @errorName(err), |
| 6964 | }); |
| 6965 | elf_file: { |
| 6966 | if (n != ld_script_bytes.items.len) break :elf_file; |
| 6967 | if (!mem.eql(u8, ld_script_bytes.items[0..4], "\x7fELF")) break :elf_file; |
| 6968 | // Appears to be an ELF file. |
| 6969 | return finishAccessLibPath(arena, create_module, test_path, link_mode, parent, lib_name); |
| 6970 | } |
| 6971 | const stat = file.stat() catch |err| |
| 6972 | fatal("failed to stat {s}: {s}", .{ test_path.items, @errorName(err) }); |
| 6973 | const size = std.math.cast(u32, stat.size) orelse |
| 6974 | fatal("{s}: linker script too big", .{test_path.items}); |
| 6975 | try ld_script_bytes.resize(gpa, size); |
| 6976 | const buf = ld_script_bytes.items[n..]; |
| 6977 | const n2 = file.readAll(buf) catch |err| |
| 6978 | fatal("failed to read {s}: {s}", .{ test_path.items, @errorName(err) }); |
| 6979 | if (n2 != buf.len) fatal("failed to read {s}: unexpected end of file", .{test_path.items}); |
| 6980 | var diags = link.Diags.init(gpa); |
| 6981 | defer diags.deinit(); |
| 6982 | const ld_script_result = link.LdScript.parse(gpa, &diags, Path.initCwd(test_path.items), ld_script_bytes.items); |
| 6983 | if (diags.hasErrors()) { |
| 6984 | var wip_errors: std.zig.ErrorBundle.Wip = undefined; |
| 6985 | try wip_errors.init(gpa); |
| 6986 | defer wip_errors.deinit(); |
| 6987 | |
| 6988 | try diags.addMessagesToBundle(&wip_errors); |
| 6989 | |
| 6990 | var error_bundle = try wip_errors.toOwnedBundle(""); |
| 6991 | defer error_bundle.deinit(gpa); |
| 6992 | |
| 6993 | const color: Color = .auto; |
| 6994 | error_bundle.renderToStdErr(color.renderOptions()); |
| 6995 | |
| 6996 | process.exit(1); |
| 6997 | } |
| 6998 | |
| 6999 | var ld_script = ld_script_result catch |err| |
| 7000 | fatal("{s}: failed to parse linker script: {s}", .{ test_path.items, @errorName(err) }); |
| 7001 | defer ld_script.deinit(gpa); |
| 7002 | |
| 7003 | try external_linker_inputs.ensureUnusedCapacity(arena, ld_script.args.len); |
| 7004 | for (ld_script.args) |arg| { |
| 7005 | const syslib: SystemLib = .{ |
| 7006 | .needed = arg.needed or parent.needed, |
| 7007 | .weak = parent.weak, |
| 7008 | .preferred_mode = parent.preferred_mode, |
| 7009 | .search_strategy = parent.search_strategy, |
| 7010 | }; |
| 7011 | if (mem.startsWith(u8, arg.path, "-l")) { |
| 7012 | external_linker_inputs.appendAssumeCapacity(.{ .named = .{ |
| 7013 | .name = try arena.dupe(u8, arg.path["-l".len..]), |
| 7014 | .info = syslib, |
| 7015 | } }); |
| 7016 | } else { |
| 7017 | external_linker_inputs.appendAssumeCapacity(.{ .path = .{ |
| 7018 | .path = Path.initCwd(try arena.dupe(u8, arg.path)), |
| 7019 | .info = syslib, |
| 7020 | } }); |
| 7021 | } |
| 7022 | } |
| 7023 | return .ok; |
| 7024 | } |
| 7025 | |
| 6896 | 7026 | fs.cwd().access(test_path.items, .{}) catch |err| switch (err) { |
| 6897 | 7027 | error.FileNotFound => break :main_check, |
| 6898 | 7028 | else => |e| fatal("unable to search for {s} library '{s}': {s}", .{ |
| 6899 | 7029 | @tagName(link_mode), test_path.items, @errorName(e), |
| 6900 | 7030 | }), |
| 6901 | 7031 | }; |
| 6902 | | return true; |
| 7032 | return finishAccessLibPath(arena, create_module, test_path, link_mode, parent, lib_name); |
| 6903 | 7033 | } |
| 6904 | 7034 | |
| 6905 | 7035 | // In the case of Darwin, the main check will be .dylib, so here we |
| 6906 | 7036 | // additionally check for .so files. |
| 6907 | 7037 | if (target.isDarwin() and link_mode == .dynamic) so: { |
| 6908 | 7038 | test_path.clearRetainingCapacity(); |
| 6909 | | try test_path.writer().print("{s}" ++ sep ++ "lib{s}.so", .{ lib_dir_path, lib_name }); |
| 6910 | | try checked_paths.writer().print("\n {s}", .{test_path.items}); |
| 7039 | try test_path.writer(gpa).print("{s}" ++ sep ++ "lib{s}.so", .{ lib_dir_path, lib_name }); |
| 7040 | try checked_paths.writer(gpa).print("\n {s}", .{test_path.items}); |
| 6911 | 7041 | fs.cwd().access(test_path.items, .{}) catch |err| switch (err) { |
| 6912 | 7042 | error.FileNotFound => break :so, |
| 6913 | 7043 | else => |e| fatal("unable to search for so library '{s}': {s}", .{ |
| 6914 | 7044 | test_path.items, @errorName(e), |
| 6915 | 7045 | }), |
| 6916 | 7046 | }; |
| 6917 | | return true; |
| 7047 | return finishAccessLibPath(arena, create_module, test_path, link_mode, parent, lib_name); |
| 6918 | 7048 | } |
| 6919 | 7049 | |
| 6920 | 7050 | // In the case of MinGW, the main check will be .lib but we also need to |
| 6921 | 7051 | // look for `libfoo.a`. |
| 6922 | 7052 | if (target.isMinGW() and link_mode == .static) mingw: { |
| 6923 | 7053 | test_path.clearRetainingCapacity(); |
| 6924 | | try test_path.writer().print("{s}" ++ sep ++ "lib{s}.a", .{ |
| 7054 | try test_path.writer(gpa).print("{s}" ++ sep ++ "lib{s}.a", .{ |
| 6925 | 7055 | lib_dir_path, lib_name, |
| 6926 | 7056 | }); |
| 6927 | | try checked_paths.writer().print("\n {s}", .{test_path.items}); |
| 7057 | try checked_paths.writer(gpa).print("\n {s}", .{test_path.items}); |
| 6928 | 7058 | fs.cwd().access(test_path.items, .{}) catch |err| switch (err) { |
| 6929 | 7059 | error.FileNotFound => break :mingw, |
| 6930 | 7060 | else => |e| fatal("unable to search for static library '{s}': {s}", .{ |
| 6931 | 7061 | test_path.items, @errorName(e), |
| 6932 | 7062 | }), |
| 6933 | 7063 | }; |
| 6934 | | return true; |
| 7064 | return finishAccessLibPath(arena, create_module, test_path, link_mode, parent, lib_name); |
| 6935 | 7065 | } |
| 6936 | 7066 | |
| 6937 | | return false; |
| 7067 | return .no_match; |
| 7068 | } |
| 7069 | |
| 7070 | fn finishAccessLibPath( |
| 7071 | arena: Allocator, |
| 7072 | create_module: *CreateModule, |
| 7073 | test_path: *std.ArrayListUnmanaged(u8), |
| 7074 | link_mode: std.builtin.LinkMode, |
| 7075 | parent: SystemLib, |
| 7076 | lib_name: []const u8, |
| 7077 | ) Allocator.Error!AccessLibPathResult { |
| 7078 | const path = Path.initCwd(try arena.dupe(u8, test_path.items)); |
| 7079 | switch (link_mode) { |
| 7080 | .static => try create_module.link_objects.append(arena, .{ .path = path }), |
| 7081 | .dynamic => try create_module.resolved_system_libs.append(arena, .{ |
| 7082 | .name = lib_name, |
| 7083 | .lib = .{ |
| 7084 | .needed = parent.needed, |
| 7085 | .weak = parent.weak, |
| 7086 | .path = path, |
| 7087 | }, |
| 7088 | }), |
| 7089 | } |
| 7090 | return .ok; |
| 6938 | 7091 | } |
| 6939 | 7092 | |
| 6940 | 7093 | fn accessFrameworkPath( |
| ... | ... | @@ -7634,3 +7787,18 @@ fn handleModArg( |
| 7634 | 7787 | c_source_files_owner_index.* = create_module.c_source_files.items.len; |
| 7635 | 7788 | rc_source_files_owner_index.* = create_module.rc_source_files.items.len; |
| 7636 | 7789 | } |
| 7790 | |
| 7791 | fn stripLibPrefixAndSuffix(path: []const u8, target: std.Target) struct { []const u8, std.builtin.LinkMode } { |
| 7792 | const prefix = target.libPrefix(); |
| 7793 | const static_suffix = target.staticLibSuffix(); |
| 7794 | const dynamic_suffix = target.dynamicLibSuffix(); |
| 7795 | const basename = fs.path.basename(path); |
| 7796 | const unlibbed = if (mem.startsWith(u8, basename, prefix)) basename[prefix.len..] else basename; |
| 7797 | if (mem.endsWith(u8, unlibbed, static_suffix)) return .{ |
| 7798 | unlibbed[0 .. unlibbed.len - static_suffix.len], .static, |
| 7799 | }; |
| 7800 | if (mem.endsWith(u8, unlibbed, dynamic_suffix)) return .{ |
| 7801 | unlibbed[0 .. unlibbed.len - dynamic_suffix.len], .dynamic, |
| 7802 | }; |
| 7803 | fatal("unrecognized library path: {s}", .{path}); |
| 7804 | } |