authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-08-21 11:01:11+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-08-21 11:01:11+02:00
log8e96be0088d4ae007589651066d426f815aaab4f
tree398f48e05e365436a16f170b3075e596f135decb
parent283afb50b56fb8a2c288d2452bdf6e595a1bbb06
parentb73ef342895f00bdb31ea5f947ee83764f235d43
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #16888 from ziglang/macho-frameworks

compiler: resolve framework paths in the frontend

8 files changed, 125 insertions(+), 139 deletions(-)

src/Compilation.zig+5-5
...@@ -507,7 +507,7 @@ pub const InitOptions = struct {...@@ -507,7 +507,7 @@ pub const InitOptions = struct {
507 c_source_files: []const CSourceFile = &[0]CSourceFile{},507 c_source_files: []const CSourceFile = &[0]CSourceFile{},
508 link_objects: []LinkObject = &[0]LinkObject{},508 link_objects: []LinkObject = &[0]LinkObject{},
509 framework_dirs: []const []const u8 = &[0][]const u8{},509 framework_dirs: []const []const u8 = &[0][]const u8{},
510 frameworks: std.StringArrayHashMapUnmanaged(Framework) = .{},510 frameworks: []const Framework = &.{},
511 system_lib_names: []const []const u8 = &.{},511 system_lib_names: []const []const u8 = &.{},
512 system_lib_infos: []const SystemLib = &.{},512 system_lib_infos: []const SystemLib = &.{},
513 /// These correspond to the WASI libc emulated subcomponents including:513 /// These correspond to the WASI libc emulated subcomponents including:
...@@ -830,7 +830,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -830,7 +830,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
830 // Our linker can't handle objects or most advanced options yet.830 // Our linker can't handle objects or most advanced options yet.
831 if (options.link_objects.len != 0 or831 if (options.link_objects.len != 0 or
832 options.c_source_files.len != 0 or832 options.c_source_files.len != 0 or
833 options.frameworks.count() != 0 or833 options.frameworks.len != 0 or
834 options.system_lib_names.len != 0 or834 options.system_lib_names.len != 0 or
835 options.link_libc or options.link_libcpp or835 options.link_libc or options.link_libcpp or
836 link_eh_frame_hdr or836 link_eh_frame_hdr or
...@@ -2267,7 +2267,7 @@ fn prepareWholeEmitSubPath(arena: Allocator, opt_emit: ?EmitLoc) error{OutOfMemo...@@ -2267,7 +2267,7 @@ fn prepareWholeEmitSubPath(arena: Allocator, opt_emit: ?EmitLoc) error{OutOfMemo
2267/// to remind the programmer to update multiple related pieces of code that2267/// to remind the programmer to update multiple related pieces of code that
2268/// are in different locations. Bump this number when adding or deleting2268/// are in different locations. Bump this number when adding or deleting
2269/// anything from the link cache manifest.2269/// anything from the link cache manifest.
2270pub const link_hash_implementation_version = 9;2270pub const link_hash_implementation_version = 10;
22712271
2272fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void {2272fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void {
2273 const gpa = comp.gpa;2273 const gpa = comp.gpa;
...@@ -2277,7 +2277,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes...@@ -2277,7 +2277,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
2277 defer arena_allocator.deinit();2277 defer arena_allocator.deinit();
2278 const arena = arena_allocator.allocator();2278 const arena = arena_allocator.allocator();
22792279
2280 comptime assert(link_hash_implementation_version == 9);2280 comptime assert(link_hash_implementation_version == 10);
22812281
2282 if (comp.bin_file.options.module) |mod| {2282 if (comp.bin_file.options.module) |mod| {
2283 const main_zig_file = try mod.main_pkg.root_src_directory.join(arena, &[_][]const u8{2283 const main_zig_file = try mod.main_pkg.root_src_directory.join(arena, &[_][]const u8{
...@@ -2386,7 +2386,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes...@@ -2386,7 +2386,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
23862386
2387 // Mach-O specific stuff2387 // Mach-O specific stuff
2388 man.hash.addListOfBytes(comp.bin_file.options.framework_dirs);2388 man.hash.addListOfBytes(comp.bin_file.options.framework_dirs);
2389 link.hashAddFrameworks(&man.hash, comp.bin_file.options.frameworks);2389 try link.hashAddFrameworks(man, comp.bin_file.options.frameworks);
2390 try man.addOptionalFile(comp.bin_file.options.entitlements);2390 try man.addOptionalFile(comp.bin_file.options.entitlements);
2391 man.hash.addOptional(comp.bin_file.options.pagezero_size);2391 man.hash.addOptional(comp.bin_file.options.pagezero_size);
2392 man.hash.addOptional(comp.bin_file.options.headerpad_size);2392 man.hash.addOptional(comp.bin_file.options.headerpad_size);
src/link.zig+7-12
...@@ -37,6 +37,7 @@ pub const SystemLib = struct {...@@ -37,6 +37,7 @@ pub const SystemLib = struct {
37pub const Framework = struct {37pub const Framework = struct {
38 needed: bool = false,38 needed: bool = false,
39 weak: bool = false,39 weak: bool = false,
40 path: []const u8,
40};41};
4142
42pub const SortSection = enum { name, alignment };43pub const SortSection = enum { name, alignment };
...@@ -56,15 +57,11 @@ pub fn hashAddSystemLibs(...@@ -56,15 +57,11 @@ pub fn hashAddSystemLibs(
56 }57 }
57}58}
5859
59pub fn hashAddFrameworks(60pub fn hashAddFrameworks(man: *Cache.Manifest, hm: []const Framework) !void {
60 hh: *Cache.HashHelper,61 for (hm) |value| {
61 hm: std.StringArrayHashMapUnmanaged(Framework),62 man.hash.add(value.needed);
62) void {63 man.hash.add(value.weak);
63 const keys = hm.keys();64 _ = try man.addFile(value.path, null);
64 hh.addListOfBytes(keys);
65 for (hm.values()) |value| {
66 hh.add(value.needed);
67 hh.add(value.weak);
68 }65 }
69}66}
7067
...@@ -208,7 +205,7 @@ pub const Options = struct {...@@ -208,7 +205,7 @@ pub const Options = struct {
208205
209 objects: []Compilation.LinkObject,206 objects: []Compilation.LinkObject,
210 framework_dirs: []const []const u8,207 framework_dirs: []const []const u8,
211 frameworks: std.StringArrayHashMapUnmanaged(Framework),208 frameworks: []const Framework,
212 /// These are *always* dynamically linked. Static libraries will be209 /// These are *always* dynamically linked. Static libraries will be
213 /// provided as positional arguments.210 /// provided as positional arguments.
214 system_libs: std.StringArrayHashMapUnmanaged(SystemLib),211 system_libs: std.StringArrayHashMapUnmanaged(SystemLib),
...@@ -276,7 +273,6 @@ pub const Options = struct {...@@ -276,7 +273,6 @@ pub const Options = struct {
276273
277 pub fn move(self: *Options) Options {274 pub fn move(self: *Options) Options {
278 const copied_state = self.*;275 const copied_state = self.*;
279 self.frameworks = .{};
280 self.system_libs = .{};276 self.system_libs = .{};
281 self.force_undefined_symbols = .{};277 self.force_undefined_symbols = .{};
282 return copied_state;278 return copied_state;
...@@ -642,7 +638,6 @@ pub const File = struct {...@@ -642,7 +638,6 @@ pub const File = struct {
642 base.releaseLock();638 base.releaseLock();
643 if (base.file) |f| f.close();639 if (base.file) |f| f.close();
644 if (base.intermediary_basename) |sub_path| base.allocator.free(sub_path);640 if (base.intermediary_basename) |sub_path| base.allocator.free(sub_path);
645 base.options.frameworks.deinit(base.allocator);
646 base.options.system_libs.deinit(base.allocator);641 base.options.system_libs.deinit(base.allocator);
647 base.options.force_undefined_symbols.deinit(base.allocator);642 base.options.force_undefined_symbols.deinit(base.allocator);
648 switch (base.tag) {643 switch (base.tag) {
src/link/Coff/lld.zig+1-1
...@@ -63,7 +63,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -63,7 +63,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
63 man = comp.cache_parent.obtain();63 man = comp.cache_parent.obtain();
64 self.base.releaseLock();64 self.base.releaseLock();
6565
66 comptime assert(Compilation.link_hash_implementation_version == 9);66 comptime assert(Compilation.link_hash_implementation_version == 10);
6767
68 for (self.base.options.objects) |obj| {68 for (self.base.options.objects) |obj| {
69 _ = try man.addFile(obj.path, null);69 _ = try man.addFile(obj.path, null);
src/link/Elf.zig+1-1
...@@ -1367,7 +1367,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -1367,7 +1367,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
1367 // We are about to obtain this lock, so here we give other processes a chance first.1367 // We are about to obtain this lock, so here we give other processes a chance first.
1368 self.base.releaseLock();1368 self.base.releaseLock();
13691369
1370 comptime assert(Compilation.link_hash_implementation_version == 9);1370 comptime assert(Compilation.link_hash_implementation_version == 10);
13711371
1372 try man.addOptionalFile(self.base.options.linker_script);1372 try man.addOptionalFile(self.base.options.linker_script);
1373 try man.addOptionalFile(self.base.options.version_script);1373 try man.addOptionalFile(self.base.options.version_script);
src/link/MachO.zig+1-63
...@@ -870,49 +870,7 @@ fn resolveLibSystemInDirs(arena: Allocator, dirs: []const []const u8, out_libs:...@@ -870,49 +870,7 @@ fn resolveLibSystemInDirs(arena: Allocator, dirs: []const []const u8, out_libs:
870 return false;870 return false;
871}871}
872872
873pub fn resolveSearchDir(873fn resolveLib(
874 arena: Allocator,
875 dir: []const u8,
876 syslibroot: ?[]const u8,
877) !?[]const u8 {
878 var candidates = std.ArrayList([]const u8).init(arena);
879
880 if (fs.path.isAbsolute(dir)) {
881 if (syslibroot) |root| {
882 const common_dir = if (builtin.os.tag == .windows) blk: {
883 // We need to check for disk designator and strip it out from dir path so
884 // that we can concat dir with syslibroot.
885 // TODO we should backport this mechanism to 'MachO.Dylib.parseDependentLibs()'
886 const disk_designator = fs.path.diskDesignatorWindows(dir);
887
888 if (mem.indexOf(u8, dir, disk_designator)) |where| {
889 break :blk dir[where + disk_designator.len ..];
890 }
891
892 break :blk dir;
893 } else dir;
894 const full_path = try fs.path.join(arena, &[_][]const u8{ root, common_dir });
895 try candidates.append(full_path);
896 }
897 }
898
899 try candidates.append(dir);
900
901 for (candidates.items) |candidate| {
902 // Verify that search path actually exists
903 var tmp = fs.cwd().openDir(candidate, .{}) catch |err| switch (err) {
904 error.FileNotFound => continue,
905 else => |e| return e,
906 };
907 defer tmp.close();
908
909 return candidate;
910 }
911
912 return null;
913}
914
915pub fn resolveLib(
916 arena: Allocator,874 arena: Allocator,
917 search_dir: []const u8,875 search_dir: []const u8,
918 name: []const u8,876 name: []const u8,
...@@ -931,26 +889,6 @@ pub fn resolveLib(...@@ -931,26 +889,6 @@ pub fn resolveLib(
931 return full_path;889 return full_path;
932}890}
933891
934pub fn resolveFramework(
935 arena: Allocator,
936 search_dir: []const u8,
937 name: []const u8,
938 ext: []const u8,
939) !?[]const u8 {
940 const search_name = try std.fmt.allocPrint(arena, "{s}{s}", .{ name, ext });
941 const prefix_path = try std.fmt.allocPrint(arena, "{s}.framework", .{name});
942 const full_path = try fs.path.join(arena, &[_][]const u8{ search_dir, prefix_path, search_name });
943
944 // Check if the file exists.
945 const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
946 error.FileNotFound => return null,
947 else => |e| return e,
948 };
949 defer tmp.close();
950
951 return full_path;
952}
953
954const ParseDylibError = error{892const ParseDylibError = error{
955 OutOfMemory,893 OutOfMemory,
956 EmptyStubFile,894 EmptyStubFile,
src/link/MachO/zld.zig+17-53
...@@ -3396,7 +3396,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -3396,7 +3396,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
3396 // We are about to obtain this lock, so here we give other processes a chance first.3396 // We are about to obtain this lock, so here we give other processes a chance first.
3397 macho_file.base.releaseLock();3397 macho_file.base.releaseLock();
33983398
3399 comptime assert(Compilation.link_hash_implementation_version == 9);3399 comptime assert(Compilation.link_hash_implementation_version == 10);
34003400
3401 for (options.objects) |obj| {3401 for (options.objects) |obj| {
3402 _ = try man.addFile(obj.path, null);3402 _ = try man.addFile(obj.path, null);
...@@ -3417,7 +3417,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -3417,7 +3417,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
3417 man.hash.add(options.strip);3417 man.hash.add(options.strip);
3418 man.hash.addListOfBytes(options.lib_dirs);3418 man.hash.addListOfBytes(options.lib_dirs);
3419 man.hash.addListOfBytes(options.framework_dirs);3419 man.hash.addListOfBytes(options.framework_dirs);
3420 link.hashAddFrameworks(&man.hash, options.frameworks);3420 try link.hashAddFrameworks(&man, options.frameworks);
3421 man.hash.addListOfBytes(options.rpath_list);3421 man.hash.addListOfBytes(options.rpath_list);
3422 if (is_dyn_lib) {3422 if (is_dyn_lib) {
3423 man.hash.addOptionalBytes(options.install_name);3423 man.hash.addOptionalBytes(options.install_name);
...@@ -3512,9 +3512,6 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -3512,9 +3512,6 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
3512 try zld.atoms.append(gpa, Atom.empty); // AtomIndex at 0 is reserved as null atom3512 try zld.atoms.append(gpa, Atom.empty); // AtomIndex at 0 is reserved as null atom
3513 try zld.strtab.buffer.append(gpa, 0);3513 try zld.strtab.buffer.append(gpa, 0);
35143514
3515 var lib_not_found = false;
3516 var framework_not_found = false;
3517
3518 // Positional arguments to the linker such as object files and static archives.3515 // Positional arguments to the linker such as object files and static archives.
3519 var positionals = std.ArrayList([]const u8).init(arena);3516 var positionals = std.ArrayList([]const u8).init(arena);
3520 try positionals.ensureUnusedCapacity(options.objects.len);3517 try positionals.ensureUnusedCapacity(options.objects.len);
...@@ -3557,43 +3554,16 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -3557,43 +3554,16 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
3557 for (vals) |v| libs.putAssumeCapacity(v.path.?, v);3554 for (vals) |v| libs.putAssumeCapacity(v.path.?, v);
3558 }3555 }
35593556
3560 try MachO.resolveLibSystem(arena, comp, options.sysroot, target, options.lib_dirs, &libs);3557 {
35613558 try libs.ensureUnusedCapacity(options.frameworks.len);
3562 // frameworks3559 for (options.frameworks) |v| libs.putAssumeCapacity(v.path, .{
3563 var framework_dirs = std.ArrayList([]const u8).init(arena);3560 .needed = v.needed,
3564 for (options.framework_dirs) |dir| {3561 .weak = v.weak,
3565 if (try MachO.resolveSearchDir(arena, dir, options.sysroot)) |search_dir| {3562 .path = v.path,
3566 try framework_dirs.append(search_dir);3563 });
3567 } else {
3568 log.warn("directory not found for '-F{s}'", .{dir});
3569 }
3570 }
3571
3572 outer: for (options.frameworks.keys()) |f_name| {
3573 for (framework_dirs.items) |dir| {
3574 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
3575 if (try MachO.resolveFramework(arena, dir, f_name, ext)) |full_path| {
3576 const info = options.frameworks.get(f_name).?;
3577 try libs.put(full_path, .{
3578 .needed = info.needed,
3579 .weak = info.weak,
3580 .path = full_path,
3581 });
3582 continue :outer;
3583 }
3584 }
3585 } else {
3586 log.warn("framework not found for '-framework {s}'", .{f_name});
3587 framework_not_found = true;
3588 }
3589 }3564 }
35903565
3591 if (framework_not_found) {3566 try MachO.resolveLibSystem(arena, comp, options.sysroot, target, options.lib_dirs, &libs);
3592 log.warn("Framework search paths:", .{});
3593 for (framework_dirs.items) |dir| {
3594 log.warn(" {s}", .{dir});
3595 }
3596 }
35973567
3598 if (options.verbose_link) {3568 if (options.verbose_link) {
3599 var argv = std.ArrayList([]const u8).init(arena);3569 var argv = std.ArrayList([]const u8).init(arena);
...@@ -3693,14 +3663,14 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -3693,14 +3663,14 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
3693 try argv.append(try std.fmt.allocPrint(arena, "-L{s}", .{lib_dir}));3663 try argv.append(try std.fmt.allocPrint(arena, "-L{s}", .{lib_dir}));
3694 }3664 }
36953665
3696 for (options.frameworks.keys()) |framework| {3666 for (options.frameworks) |framework| {
3697 const info = options.frameworks.get(framework).?;3667 const name = std.fs.path.stem(framework.path);
3698 const arg = if (info.needed)3668 const arg = if (framework.needed)
3699 try std.fmt.allocPrint(arena, "-needed_framework {s}", .{framework})3669 try std.fmt.allocPrint(arena, "-needed_framework {s}", .{name})
3700 else if (info.weak)3670 else if (framework.weak)
3701 try std.fmt.allocPrint(arena, "-weak_framework {s}", .{framework})3671 try std.fmt.allocPrint(arena, "-weak_framework {s}", .{name})
3702 else3672 else
3703 try std.fmt.allocPrint(arena, "-framework {s}", .{framework});3673 try std.fmt.allocPrint(arena, "-framework {s}", .{name});
3704 try argv.append(arg);3674 try argv.append(arg);
3705 }3675 }
37063676
...@@ -3740,12 +3710,6 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -3740,12 +3710,6 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
3740 if (resolver.unresolved.count() > 0) {3710 if (resolver.unresolved.count() > 0) {
3741 return error.UndefinedSymbolReference;3711 return error.UndefinedSymbolReference;
3742 }3712 }
3743 if (lib_not_found) {
3744 return error.LibraryNotFound;
3745 }
3746 if (framework_not_found) {
3747 return error.FrameworkNotFound;
3748 }
37493713
3750 if (options.output_mode == .Exe) {3714 if (options.output_mode == .Exe) {
3751 const entry_name = options.entry orelse load_commands.default_entry_point;3715 const entry_name = options.entry orelse load_commands.default_entry_point;
src/link/Wasm.zig+2-2
...@@ -3193,7 +3193,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l...@@ -3193,7 +3193,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
3193 // We are about to obtain this lock, so here we give other processes a chance first.3193 // We are about to obtain this lock, so here we give other processes a chance first.
3194 wasm.base.releaseLock();3194 wasm.base.releaseLock();
31953195
3196 comptime assert(Compilation.link_hash_implementation_version == 9);3196 comptime assert(Compilation.link_hash_implementation_version == 10);
31973197
3198 for (options.objects) |obj| {3198 for (options.objects) |obj| {
3199 _ = try man.addFile(obj.path, null);3199 _ = try man.addFile(obj.path, null);
...@@ -4254,7 +4254,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -4254,7 +4254,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
4254 // We are about to obtain this lock, so here we give other processes a chance first.4254 // We are about to obtain this lock, so here we give other processes a chance first.
4255 wasm.base.releaseLock();4255 wasm.base.releaseLock();
42564256
4257 comptime assert(Compilation.link_hash_implementation_version == 9);4257 comptime assert(Compilation.link_hash_implementation_version == 10);
42584258
4259 for (wasm.base.options.objects) |obj| {4259 for (wasm.base.options.objects) |obj| {
4260 _ = try man.addFile(obj.path, null);4260 _ = try man.addFile(obj.path, null);
src/main.zig+91-2
...@@ -746,6 +746,13 @@ const SystemLib = struct {...@@ -746,6 +746,13 @@ const SystemLib = struct {
746 }746 }
747};747};
748748
749/// Similar to `link.Framework` except it doesn't store yet unresolved
750/// path to the framework.
751const Framework = struct {
752 needed: bool = false,
753 weak: bool = false,
754};
755
749const CliModule = struct {756const CliModule = struct {
750 mod: *Package,757 mod: *Package,
751 /// still in CLI arg format758 /// still in CLI arg format
...@@ -919,7 +926,7 @@ fn buildOutputType(...@@ -919,7 +926,7 @@ fn buildOutputType(
919 var c_source_files = std.ArrayList(Compilation.CSourceFile).init(arena);926 var c_source_files = std.ArrayList(Compilation.CSourceFile).init(arena);
920 var link_objects = std.ArrayList(Compilation.LinkObject).init(arena);927 var link_objects = std.ArrayList(Compilation.LinkObject).init(arena);
921 var framework_dirs = std.ArrayList([]const u8).init(arena);928 var framework_dirs = std.ArrayList([]const u8).init(arena);
922 var frameworks: std.StringArrayHashMapUnmanaged(Compilation.Framework) = .{};929 var frameworks: std.StringArrayHashMapUnmanaged(Framework) = .{};
923 // null means replace with the test executable binary930 // null means replace with the test executable binary
924 var test_exec_args = std.ArrayList(?[]const u8).init(arena);931 var test_exec_args = std.ArrayList(?[]const u8).init(arena);
925 var linker_export_symbol_names = std.ArrayList([]const u8).init(arena);932 var linker_export_symbol_names = std.ArrayList([]const u8).init(arena);
...@@ -2868,6 +2875,59 @@ fn buildOutputType(...@@ -2868,6 +2875,59 @@ fn buildOutputType(
2868 }2875 }
2869 // After this point, resolved_system_libs is used instead of external_system_libs.2876 // After this point, resolved_system_libs is used instead of external_system_libs.
28702877
2878 // We now repeat part of the process for frameworks.
2879 var resolved_frameworks = std.ArrayList(Compilation.Framework).init(arena);
2880
2881 if (frameworks.keys().len > 0) {
2882 var test_path = std.ArrayList(u8).init(gpa);
2883 defer test_path.deinit();
2884
2885 var checked_paths = std.ArrayList(u8).init(gpa);
2886 defer checked_paths.deinit();
2887
2888 var failed_frameworks = std.ArrayList(struct {
2889 name: []const u8,
2890 checked_paths: []const u8,
2891 }).init(arena);
2892
2893 framework: for (frameworks.keys(), frameworks.values()) |framework_name, info| {
2894 checked_paths.clearRetainingCapacity();
2895
2896 for (framework_dirs.items) |framework_dir_path| {
2897 if (try accessFrameworkPath(
2898 &test_path,
2899 &checked_paths,
2900 framework_dir_path,
2901 framework_name,
2902 )) {
2903 const path = try arena.dupe(u8, test_path.items);
2904 try resolved_frameworks.append(.{
2905 .needed = info.needed,
2906 .weak = info.weak,
2907 .path = path,
2908 });
2909 continue :framework;
2910 }
2911 }
2912
2913 try failed_frameworks.append(.{
2914 .name = framework_name,
2915 .checked_paths = try arena.dupe(u8, checked_paths.items),
2916 });
2917 }
2918
2919 if (failed_frameworks.items.len > 0) {
2920 for (failed_frameworks.items) |f| {
2921 const searched_paths = if (f.checked_paths.len == 0) " none" else f.checked_paths;
2922 std.log.err("unable to find framework '{s}'. searched paths: {s}", .{
2923 f.name, searched_paths,
2924 });
2925 }
2926 process.exit(1);
2927 }
2928 }
2929 // After this point, resolved_frameworks is used instead of frameworks.
2930
2871 const object_format = target_info.target.ofmt;2931 const object_format = target_info.target.ofmt;
28722932
2873 if (output_mode == .Obj and (object_format == .coff or object_format == .macho)) {2933 if (output_mode == .Obj and (object_format == .coff or object_format == .macho)) {
...@@ -3261,7 +3321,7 @@ fn buildOutputType(...@@ -3261,7 +3321,7 @@ fn buildOutputType(
3261 .c_source_files = c_source_files.items,3321 .c_source_files = c_source_files.items,
3262 .link_objects = link_objects.items,3322 .link_objects = link_objects.items,
3263 .framework_dirs = framework_dirs.items,3323 .framework_dirs = framework_dirs.items,
3264 .frameworks = frameworks,3324 .frameworks = resolved_frameworks.items,
3265 .system_lib_names = resolved_system_libs.items(.name),3325 .system_lib_names = resolved_system_libs.items(.name),
3266 .system_lib_infos = resolved_system_libs.items(.lib),3326 .system_lib_infos = resolved_system_libs.items(.lib),
3267 .wasi_emulated_libs = wasi_emulated_libs.items,3327 .wasi_emulated_libs = wasi_emulated_libs.items,
...@@ -6336,3 +6396,32 @@ fn accessLibPath(...@@ -6336,3 +6396,32 @@ fn accessLibPath(
63366396
6337 return false;6397 return false;
6338}6398}
6399
6400fn accessFrameworkPath(
6401 test_path: *std.ArrayList(u8),
6402 checked_paths: *std.ArrayList(u8),
6403 framework_dir_path: []const u8,
6404 framework_name: []const u8,
6405) !bool {
6406 const sep = fs.path.sep_str;
6407
6408 for (&[_][]const u8{ "tbd", "dylib" }) |ext| {
6409 test_path.clearRetainingCapacity();
6410 try test_path.writer().print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}.{s}", .{
6411 framework_dir_path,
6412 framework_name,
6413 framework_name,
6414 ext,
6415 });
6416 try checked_paths.writer().print("\n {s}", .{test_path.items});
6417 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
6418 error.FileNotFound => continue,
6419 else => |e| fatal("unable to search for {s} framework '{s}': {s}", .{
6420 ext, test_path.items, @errorName(e),
6421 }),
6422 };
6423 return true;
6424 }
6425
6426 return false;
6427}