| author | |
| committer | |
| log | 0078d36ff39f2ef35e32f2d58e5d447b62f3a37e |
| tree | 37793e2032189f83915a829dac0bd425264b488e |
| parent | 905a18849f7f2c3f269fbf425170e0c86b12524a |
| parent | 8f00bc9d231c0c686b2ffa3bd0b14181afa7a171 |
| signature |
macho: implement `-search_paths_first` and `-search_dylibs_first`12 files changed, 233 insertions(+), 63 deletions(-)
lib/std/build.zig+11| ... | ... | @@ -1586,6 +1586,13 @@ pub const LibExeObjStep = struct { |
| 1586 | 1586 | /// (Darwin) Size of the pagezero segment. |
| 1587 | 1587 | pagezero_size: ?u64 = null, |
| 1588 | 1588 | |
| 1589 | /// (Darwin) Search strategy for searching system libraries. Either `paths_first` or `dylibs_first`. | |
| 1590 | /// The former lowers to `-search_paths_first` linker option, while the latter to `-search_dylibs_first` | |
| 1591 | /// option. | |
| 1592 | /// By default, if no option is specified, the linker assumes `paths_first` as the default | |
| 1593 | /// search strategy. | |
| 1594 | search_strategy: ?enum { paths_first, dylibs_first } = null, | |
| 1595 | ||
| 1589 | 1596 | /// Position Independent Code |
| 1590 | 1597 | force_pic: ?bool = null, |
| 1591 | 1598 | |
| ... | ... | @@ -2650,6 +2657,10 @@ pub const LibExeObjStep = struct { |
| 2650 | 2657 | const size = try std.fmt.allocPrint(builder.allocator, "{x}", .{pagezero_size}); |
| 2651 | 2658 | try zig_args.appendSlice(&[_][]const u8{ "-pagezero_size", size }); |
| 2652 | 2659 | } |
| 2660 | if (self.search_strategy) |strat| switch (strat) { | |
| 2661 | .paths_first => try zig_args.append("-search_paths_first"), | |
| 2662 | .dylibs_first => try zig_args.append("-search_dylibs_first"), | |
| 2663 | }; | |
| 2653 | 2664 | |
| 2654 | 2665 | if (self.bundle_compiler_rt) |x| { |
| 2655 | 2666 | if (x) { |
src/Compilation.zig+6-2| ... | ... | @@ -905,6 +905,8 @@ pub const InitOptions = struct { |
| 905 | 905 | entitlements: ?[]const u8 = null, |
| 906 | 906 | /// (Darwin) size of the __PAGEZERO segment |
| 907 | 907 | pagezero_size: ?u64 = null, |
| 908 | /// (Darwin) search strategy for system libraries | |
| 909 | search_strategy: ?link.File.MachO.SearchStrategy = null, | |
| 908 | 910 | }; |
| 909 | 911 | |
| 910 | 912 | fn addPackageTableToCacheHash( |
| ... | ... | @@ -1745,6 +1747,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1745 | 1747 | .install_name = options.install_name, |
| 1746 | 1748 | .entitlements = options.entitlements, |
| 1747 | 1749 | .pagezero_size = options.pagezero_size, |
| 1750 | .search_strategy = options.search_strategy, | |
| 1748 | 1751 | }); |
| 1749 | 1752 | errdefer bin_file.destroy(); |
| 1750 | 1753 | comp.* = .{ |
| ... | ... | @@ -2360,7 +2363,7 @@ fn prepareWholeEmitSubPath(arena: Allocator, opt_emit: ?EmitLoc) error{OutOfMemo |
| 2360 | 2363 | /// to remind the programmer to update multiple related pieces of code that |
| 2361 | 2364 | /// are in different locations. Bump this number when adding or deleting |
| 2362 | 2365 | /// anything from the link cache manifest. |
| 2363 | pub const link_hash_implementation_version = 4; | |
| 2366 | pub const link_hash_implementation_version = 5; | |
| 2364 | 2367 | |
| 2365 | 2368 | fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void { |
| 2366 | 2369 | const gpa = comp.gpa; |
| ... | ... | @@ -2370,7 +2373,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes |
| 2370 | 2373 | defer arena_allocator.deinit(); |
| 2371 | 2374 | const arena = arena_allocator.allocator(); |
| 2372 | 2375 | |
| 2373 | comptime assert(link_hash_implementation_version == 4); | |
| 2376 | comptime assert(link_hash_implementation_version == 5); | |
| 2374 | 2377 | |
| 2375 | 2378 | if (comp.bin_file.options.module) |mod| { |
| 2376 | 2379 | const main_zig_file = try mod.main_pkg.root_src_directory.join(arena, &[_][]const u8{ |
| ... | ... | @@ -2476,6 +2479,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes |
| 2476 | 2479 | man.hash.addListOfBytes(comp.bin_file.options.frameworks); |
| 2477 | 2480 | try man.addOptionalFile(comp.bin_file.options.entitlements); |
| 2478 | 2481 | man.hash.addOptional(comp.bin_file.options.pagezero_size); |
| 2482 | man.hash.addOptional(comp.bin_file.options.search_strategy); | |
| 2479 | 2483 | |
| 2480 | 2484 | // COFF specific stuff |
| 2481 | 2485 | man.hash.addOptional(comp.bin_file.options.subsystem); |
src/link.zig+3| ... | ... | @@ -190,6 +190,9 @@ pub const Options = struct { |
| 190 | 190 | /// (Darwin) size of the __PAGEZERO segment |
| 191 | 191 | pagezero_size: ?u64 = null, |
| 192 | 192 | |
| 193 | /// (Darwin) search strategy for system libraries | |
| 194 | search_strategy: ?File.MachO.SearchStrategy = null, | |
| 195 | ||
| 193 | 196 | pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode { |
| 194 | 197 | return if (options.use_lld) .Obj else options.output_mode; |
| 195 | 198 | } |
src/link/Coff.zig+1-1| ... | ... | @@ -969,7 +969,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) ! |
| 969 | 969 | man = comp.cache_parent.obtain(); |
| 970 | 970 | self.base.releaseLock(); |
| 971 | 971 | |
| 972 | comptime assert(Compilation.link_hash_implementation_version == 4); | |
| 972 | comptime assert(Compilation.link_hash_implementation_version == 5); | |
| 973 | 973 | |
| 974 | 974 | for (self.base.options.objects) |obj| { |
| 975 | 975 | _ = try man.addFile(obj.path, null); |
src/link/Elf.zig+1-1| ... | ... | @@ -1298,7 +1298,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v |
| 1298 | 1298 | // We are about to obtain this lock, so here we give other processes a chance first. |
| 1299 | 1299 | self.base.releaseLock(); |
| 1300 | 1300 | |
| 1301 | comptime assert(Compilation.link_hash_implementation_version == 4); | |
| 1301 | comptime assert(Compilation.link_hash_implementation_version == 5); | |
| 1302 | 1302 | |
| 1303 | 1303 | try man.addOptionalFile(self.base.options.linker_script); |
| 1304 | 1304 | try man.addOptionalFile(self.base.options.version_script); |
src/link/MachO.zig+109-58| ... | ... | @@ -47,6 +47,11 @@ pub const DebugSymbols = @import("MachO/DebugSymbols.zig"); |
| 47 | 47 | |
| 48 | 48 | pub const base_tag: File.Tag = File.Tag.macho; |
| 49 | 49 | |
| 50 | pub const SearchStrategy = enum { | |
| 51 | paths_first, | |
| 52 | dylibs_first, | |
| 53 | }; | |
| 54 | ||
| 50 | 55 | base: File, |
| 51 | 56 | |
| 52 | 57 | /// If this is not null, an object file is created by LLVM and linked with LLD afterwards. |
| ... | ... | @@ -536,7 +541,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 536 | 541 | // We are about to obtain this lock, so here we give other processes a chance first. |
| 537 | 542 | self.base.releaseLock(); |
| 538 | 543 | |
| 539 | comptime assert(Compilation.link_hash_implementation_version == 4); | |
| 544 | comptime assert(Compilation.link_hash_implementation_version == 5); | |
| 540 | 545 | |
| 541 | 546 | for (self.base.options.objects) |obj| { |
| 542 | 547 | _ = try man.addFile(obj.path, null); |
| ... | ... | @@ -550,6 +555,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 550 | 555 | // installation sources because they are always a product of the compiler version + target information. |
| 551 | 556 | man.hash.add(stack_size); |
| 552 | 557 | man.hash.addOptional(self.base.options.pagezero_size); |
| 558 | man.hash.addOptional(self.base.options.search_strategy); | |
| 553 | 559 | man.hash.addListOfBytes(self.base.options.lib_dirs); |
| 554 | 560 | man.hash.addListOfBytes(self.base.options.framework_dirs); |
| 555 | 561 | man.hash.addListOfBytes(self.base.options.frameworks); |
| ... | ... | @@ -784,18 +790,43 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 784 | 790 | } |
| 785 | 791 | |
| 786 | 792 | var libs = std.ArrayList([]const u8).init(arena); |
| 787 | for (search_lib_names.items) |lib_name| { | |
| 788 | // Assume ld64 default: -search_paths_first | |
| 789 | // Look in each directory for a dylib (stub first), and then for archive | |
| 790 | // TODO implement alternative: -search_dylibs_first | |
| 791 | for (&[_][]const u8{ ".tbd", ".dylib", ".a" }) |ext| { | |
| 792 | if (try resolveLib(arena, lib_dirs.items, lib_name, ext)) |full_path| { | |
| 793 | try libs.append(full_path); | |
| 794 | break; | |
| 795 | } | |
| 796 | } else { | |
| 797 | log.warn("library not found for '-l{s}'", .{lib_name}); | |
| 798 | lib_not_found = true; | |
| 793 | ||
| 794 | // Assume ld64 default -search_paths_first if no strategy specified. | |
| 795 | const search_strategy = self.base.options.search_strategy orelse .paths_first; | |
| 796 | outer: for (search_lib_names.items) |lib_name| { | |
| 797 | switch (search_strategy) { | |
| 798 | .paths_first => { | |
| 799 | // Look in each directory for a dylib (stub first), and then for archive | |
| 800 | for (lib_dirs.items) |dir| { | |
| 801 | for (&[_][]const u8{ ".tbd", ".dylib", ".a" }) |ext| { | |
| 802 | if (try resolveLib(arena, dir, lib_name, ext)) |full_path| { | |
| 803 | try libs.append(full_path); | |
| 804 | continue :outer; | |
| 805 | } | |
| 806 | } | |
| 807 | } else { | |
| 808 | log.warn("library not found for '-l{s}'", .{lib_name}); | |
| 809 | lib_not_found = true; | |
| 810 | } | |
| 811 | }, | |
| 812 | .dylibs_first => { | |
| 813 | // First, look for a dylib in each search dir | |
| 814 | for (lib_dirs.items) |dir| { | |
| 815 | for (&[_][]const u8{ ".tbd", ".dylib" }) |ext| { | |
| 816 | if (try resolveLib(arena, dir, lib_name, ext)) |full_path| { | |
| 817 | try libs.append(full_path); | |
| 818 | continue :outer; | |
| 819 | } | |
| 820 | } | |
| 821 | } else for (lib_dirs.items) |dir| { | |
| 822 | if (try resolveLib(arena, dir, lib_name, ".a")) |full_path| { | |
| 823 | try libs.append(full_path); | |
| 824 | } else { | |
| 825 | log.warn("library not found for '-l{s}'", .{lib_name}); | |
| 826 | lib_not_found = true; | |
| 827 | } | |
| 828 | } | |
| 829 | }, | |
| 799 | 830 | } |
| 800 | 831 | } |
| 801 | 832 | |
| ... | ... | @@ -811,19 +842,23 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 811 | 842 | if (self.base.options.sysroot != null) blk: { |
| 812 | 843 | // Try stub file first. If we hit it, then we're done as the stub file |
| 813 | 844 | // re-exports every single symbol definition. |
| 814 | if (try resolveLib(arena, lib_dirs.items, "System", ".tbd")) |full_path| { | |
| 815 | try libs.append(full_path); | |
| 816 | libsystem_available = true; | |
| 817 | break :blk; | |
| 845 | for (lib_dirs.items) |dir| { | |
| 846 | if (try resolveLib(arena, dir, "System", ".tbd")) |full_path| { | |
| 847 | try libs.append(full_path); | |
| 848 | libsystem_available = true; | |
| 849 | break :blk; | |
| 850 | } | |
| 818 | 851 | } |
| 819 | 852 | // If we didn't hit the stub file, try .dylib next. However, libSystem.dylib |
| 820 | 853 | // doesn't export libc.dylib which we'll need to resolve subsequently also. |
| 821 | if (try resolveLib(arena, lib_dirs.items, "System", ".dylib")) |libsystem_path| { | |
| 822 | if (try resolveLib(arena, lib_dirs.items, "c", ".dylib")) |libc_path| { | |
| 823 | try libs.append(libsystem_path); | |
| 824 | try libs.append(libc_path); | |
| 825 | libsystem_available = true; | |
| 826 | break :blk; | |
| 854 | for (lib_dirs.items) |dir| { | |
| 855 | if (try resolveLib(arena, dir, "System", ".dylib")) |libsystem_path| { | |
| 856 | if (try resolveLib(arena, dir, "c", ".dylib")) |libc_path| { | |
| 857 | try libs.append(libsystem_path); | |
| 858 | try libs.append(libc_path); | |
| 859 | libsystem_available = true; | |
| 860 | break :blk; | |
| 861 | } | |
| 827 | 862 | } |
| 828 | 863 | } |
| 829 | 864 | } |
| ... | ... | @@ -847,11 +882,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 847 | 882 | } |
| 848 | 883 | } |
| 849 | 884 | |
| 850 | for (self.base.options.frameworks) |framework| { | |
| 851 | for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| { | |
| 852 | if (try resolveFramework(arena, framework_dirs.items, framework, ext)) |full_path| { | |
| 853 | try libs.append(full_path); | |
| 854 | break; | |
| 885 | outer: for (self.base.options.frameworks) |framework| { | |
| 886 | for (framework_dirs.items) |dir| { | |
| 887 | for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| { | |
| 888 | if (try resolveFramework(arena, dir, framework, ext)) |full_path| { | |
| 889 | try libs.append(full_path); | |
| 890 | continue :outer; | |
| 891 | } | |
| 855 | 892 | } |
| 856 | 893 | } else { |
| 857 | 894 | log.warn("framework not found for '-framework {s}'", .{framework}); |
| ... | ... | @@ -934,12 +971,36 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 934 | 971 | try argv.append(try std.fmt.allocPrint(arena, "0x{x}", .{pagezero_size})); |
| 935 | 972 | } |
| 936 | 973 | |
| 974 | if (self.base.options.search_strategy) |strat| switch (strat) { | |
| 975 | .paths_first => try argv.append("-search_paths_first"), | |
| 976 | .dylibs_first => try argv.append("-search_dylibs_first"), | |
| 977 | }; | |
| 978 | ||
| 937 | 979 | if (self.base.options.entry) |entry| { |
| 938 | 980 | try argv.append("-e"); |
| 939 | 981 | try argv.append(entry); |
| 940 | 982 | } |
| 941 | 983 | |
| 942 | try argv.appendSlice(positionals.items); | |
| 984 | for (self.base.options.objects) |obj| { | |
| 985 | try argv.append(obj.path); | |
| 986 | } | |
| 987 | ||
| 988 | for (comp.c_object_table.keys()) |key| { | |
| 989 | try argv.append(key.status.success.object_path); | |
| 990 | } | |
| 991 | ||
| 992 | if (module_obj_path) |p| { | |
| 993 | try argv.append(p); | |
| 994 | } | |
| 995 | ||
| 996 | if (comp.compiler_rt_lib) |lib| { | |
| 997 | try argv.append(lib.full_object_path); | |
| 998 | } | |
| 999 | ||
| 1000 | if (self.base.options.link_libcpp) { | |
| 1001 | try argv.append(comp.libcxxabi_static_lib.?.full_object_path); | |
| 1002 | try argv.append(comp.libcxx_static_lib.?.full_object_path); | |
| 1003 | } | |
| 943 | 1004 | |
| 944 | 1005 | try argv.append("-o"); |
| 945 | 1006 | try argv.append(full_out_path); |
| ... | ... | @@ -947,7 +1008,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 947 | 1008 | try argv.append("-lSystem"); |
| 948 | 1009 | try argv.append("-lc"); |
| 949 | 1010 | |
| 950 | for (search_lib_names.items) |l_name| { | |
| 1011 | for (self.base.options.system_libs.keys()) |l_name| { | |
| 951 | 1012 | try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{l_name})); |
| 952 | 1013 | } |
| 953 | 1014 | |
| ... | ... | @@ -1183,51 +1244,41 @@ fn resolveSearchDir( |
| 1183 | 1244 | |
| 1184 | 1245 | fn resolveLib( |
| 1185 | 1246 | arena: Allocator, |
| 1186 | search_dirs: []const []const u8, | |
| 1247 | search_dir: []const u8, | |
| 1187 | 1248 | name: []const u8, |
| 1188 | 1249 | ext: []const u8, |
| 1189 | 1250 | ) !?[]const u8 { |
| 1190 | 1251 | const search_name = try std.fmt.allocPrint(arena, "lib{s}{s}", .{ name, ext }); |
| 1252 | const full_path = try fs.path.join(arena, &[_][]const u8{ search_dir, search_name }); | |
| 1191 | 1253 | |
| 1192 | for (search_dirs) |dir| { | |
| 1193 | const full_path = try fs.path.join(arena, &[_][]const u8{ dir, search_name }); | |
| 1194 | ||
| 1195 | // Check if the file exists. | |
| 1196 | const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { | |
| 1197 | error.FileNotFound => continue, | |
| 1198 | else => |e| return e, | |
| 1199 | }; | |
| 1200 | defer tmp.close(); | |
| 1201 | ||
| 1202 | return full_path; | |
| 1203 | } | |
| 1254 | // Check if the file exists. | |
| 1255 | const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { | |
| 1256 | error.FileNotFound => return null, | |
| 1257 | else => |e| return e, | |
| 1258 | }; | |
| 1259 | defer tmp.close(); | |
| 1204 | 1260 | |
| 1205 | return null; | |
| 1261 | return full_path; | |
| 1206 | 1262 | } |
| 1207 | 1263 | |
| 1208 | 1264 | fn resolveFramework( |
| 1209 | 1265 | arena: Allocator, |
| 1210 | search_dirs: []const []const u8, | |
| 1266 | search_dir: []const u8, | |
| 1211 | 1267 | name: []const u8, |
| 1212 | 1268 | ext: []const u8, |
| 1213 | 1269 | ) !?[]const u8 { |
| 1214 | 1270 | const search_name = try std.fmt.allocPrint(arena, "{s}{s}", .{ name, ext }); |
| 1215 | 1271 | const prefix_path = try std.fmt.allocPrint(arena, "{s}.framework", .{name}); |
| 1272 | const full_path = try fs.path.join(arena, &[_][]const u8{ search_dir, prefix_path, search_name }); | |
| 1216 | 1273 | |
| 1217 | for (search_dirs) |dir| { | |
| 1218 | const full_path = try fs.path.join(arena, &[_][]const u8{ dir, prefix_path, search_name }); | |
| 1219 | ||
| 1220 | // Check if the file exists. | |
| 1221 | const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { | |
| 1222 | error.FileNotFound => continue, | |
| 1223 | else => |e| return e, | |
| 1224 | }; | |
| 1225 | defer tmp.close(); | |
| 1226 | ||
| 1227 | return full_path; | |
| 1228 | } | |
| 1274 | // Check if the file exists. | |
| 1275 | const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { | |
| 1276 | error.FileNotFound => return null, | |
| 1277 | else => |e| return e, | |
| 1278 | }; | |
| 1279 | defer tmp.close(); | |
| 1229 | 1280 | |
| 1230 | return null; | |
| 1281 | return full_path; | |
| 1231 | 1282 | } |
| 1232 | 1283 | |
| 1233 | 1284 | fn parseObject(self: *MachO, path: []const u8) !bool { |
src/link/Wasm.zig+1-1| ... | ... | @@ -2481,7 +2481,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! |
| 2481 | 2481 | // We are about to obtain this lock, so here we give other processes a chance first. |
| 2482 | 2482 | self.base.releaseLock(); |
| 2483 | 2483 | |
| 2484 | comptime assert(Compilation.link_hash_implementation_version == 4); | |
| 2484 | comptime assert(Compilation.link_hash_implementation_version == 5); | |
| 2485 | 2485 | |
| 2486 | 2486 | for (self.base.options.objects) |obj| { |
| 2487 | 2487 | _ = try man.addFile(obj.path, null); |
src/main.zig+13| ... | ... | @@ -448,6 +448,8 @@ const usage_build_generic = |
| 448 | 448 | \\ -install_name=[value] (Darwin) add dylib's install name |
| 449 | 449 | \\ --entitlements [path] (Darwin) add path to entitlements file for embedding in code signature |
| 450 | 450 | \\ -pagezero_size [value] (Darwin) size of the __PAGEZERO segment in hexadecimal notation |
| 451 | \\ -search_paths_first (Darwin) search each dir in library search paths for `libx.dylib` then `libx.a` | |
| 452 | \\ -search_dylibs_first (Darwin) search `libx.dylib` in each dir in library search paths, then `libx.a` | |
| 451 | 453 | \\ --import-memory (WebAssembly) import memory from the environment |
| 452 | 454 | \\ --import-table (WebAssembly) import function table from the host environment |
| 453 | 455 | \\ --export-table (WebAssembly) export function table to the host environment |
| ... | ... | @@ -696,6 +698,7 @@ fn buildOutputType( |
| 696 | 698 | var hash_style: link.HashStyle = .both; |
| 697 | 699 | var entitlements: ?[]const u8 = null; |
| 698 | 700 | var pagezero_size: ?u64 = null; |
| 701 | var search_strategy: ?link.File.MachO.SearchStrategy = null; | |
| 699 | 702 | |
| 700 | 703 | // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names. |
| 701 | 704 | // This array is populated by zig cc frontend and then has to be converted to zig-style |
| ... | ... | @@ -917,6 +920,10 @@ fn buildOutputType( |
| 917 | 920 | pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| { |
| 918 | 921 | fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) }); |
| 919 | 922 | }; |
| 923 | } else if (mem.eql(u8, arg, "-search_paths_first")) { | |
| 924 | search_strategy = .paths_first; | |
| 925 | } else if (mem.eql(u8, arg, "-search_dylibs_first")) { | |
| 926 | search_strategy = .dylibs_first; | |
| 920 | 927 | } else if (mem.eql(u8, arg, "-T") or mem.eql(u8, arg, "--script")) { |
| 921 | 928 | linker_script = args_iter.next() orelse { |
| 922 | 929 | fatal("expected parameter after {s}", .{arg}); |
| ... | ... | @@ -1475,6 +1482,10 @@ fn buildOutputType( |
| 1475 | 1482 | mem.eql(u8, linker_arg, "-static")) |
| 1476 | 1483 | { |
| 1477 | 1484 | force_static_libs = true; |
| 1485 | } else if (mem.eql(u8, linker_arg, "-search_paths_first")) { | |
| 1486 | search_strategy = .paths_first; | |
| 1487 | } else if (mem.eql(u8, linker_arg, "-search_dylibs_first")) { | |
| 1488 | search_strategy = .dylibs_first; | |
| 1478 | 1489 | } else { |
| 1479 | 1490 | try linker_args.append(linker_arg); |
| 1480 | 1491 | } |
| ... | ... | @@ -2141,6 +2152,7 @@ fn buildOutputType( |
| 2141 | 2152 | } |
| 2142 | 2153 | |
| 2143 | 2154 | for (lib_dirs.items) |lib_dir_path| { |
| 2155 | if (cross_target.isDarwin()) break; // Targeting Darwin we let the linker resolve the libraries in the correct order | |
| 2144 | 2156 | test_path.clearRetainingCapacity(); |
| 2145 | 2157 | try test_path.writer().print("{s}" ++ sep ++ "{s}{s}{s}", .{ |
| 2146 | 2158 | lib_dir_path, |
| ... | ... | @@ -2782,6 +2794,7 @@ fn buildOutputType( |
| 2782 | 2794 | .install_name = install_name, |
| 2783 | 2795 | .entitlements = entitlements, |
| 2784 | 2796 | .pagezero_size = pagezero_size, |
| 2797 | .search_strategy = search_strategy, | |
| 2785 | 2798 | }) catch |err| switch (err) { |
| 2786 | 2799 | error.LibCUnavailable => { |
| 2787 | 2800 | const target = target_info.target; |
test/link.zig+4| ... | ... | @@ -60,5 +60,9 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 60 | 60 | cases.addBuildFile("test/link/macho/stack_size/build.zig", .{ |
| 61 | 61 | .build_modes = true, |
| 62 | 62 | }); |
| 63 | ||
| 64 | cases.addBuildFile("test/link/macho/search_strategy/build.zig", .{ | |
| 65 | .build_modes = true, | |
| 66 | }); | |
| 63 | 67 | } |
| 64 | 68 | } |
test/link/macho/search_strategy/a.c created+7| ... | ... | @@ -0,0 +1,7 @@ |
| 1 | #include <stdio.h> | |
| 2 | ||
| 3 | char world[] = "world"; | |
| 4 | ||
| 5 | char* hello() { | |
| 6 | return "Hello"; | |
| 7 | } |
test/link/macho/search_strategy/build.zig created+68| ... | ... | @@ -0,0 +1,68 @@ |
| 1 | const std = @import("std"); | |
| 2 | const Builder = std.build.Builder; | |
| 3 | const LibExeObjectStep = std.build.LibExeObjStep; | |
| 4 | ||
| 5 | pub fn build(b: *Builder) void { | |
| 6 | const mode = b.standardReleaseOptions(); | |
| 7 | ||
| 8 | const test_step = b.step("test", "Test"); | |
| 9 | test_step.dependOn(b.getInstallStep()); | |
| 10 | ||
| 11 | { | |
| 12 | // -search_dylibs_first | |
| 13 | const exe = createScenario(b, mode); | |
| 14 | exe.search_strategy = .dylibs_first; | |
| 15 | ||
| 16 | const check = exe.checkObject(.macho); | |
| 17 | check.checkStart("cmd LOAD_DYLIB"); | |
| 18 | check.checkNext("name @rpath/liba.dylib"); | |
| 19 | ||
| 20 | test_step.dependOn(&check.step); | |
| 21 | ||
| 22 | const run = exe.run(); | |
| 23 | run.cwd = b.pathFromRoot("."); | |
| 24 | run.expectStdOutEqual("Hello world"); | |
| 25 | test_step.dependOn(&run.step); | |
| 26 | } | |
| 27 | ||
| 28 | { | |
| 29 | // -search_paths_first | |
| 30 | const exe = createScenario(b, mode); | |
| 31 | exe.search_strategy = .paths_first; | |
| 32 | ||
| 33 | const run = exe.run(); | |
| 34 | run.cwd = b.pathFromRoot("."); | |
| 35 | run.expectStdOutEqual("Hello world"); | |
| 36 | test_step.dependOn(&run.step); | |
| 37 | } | |
| 38 | } | |
| 39 | ||
| 40 | fn createScenario(b: *Builder, mode: std.builtin.Mode) *LibExeObjectStep { | |
| 41 | const static = b.addStaticLibrary("a", null); | |
| 42 | static.setBuildMode(mode); | |
| 43 | static.addCSourceFile("a.c", &.{}); | |
| 44 | static.linkLibC(); | |
| 45 | static.override_dest_dir = std.build.InstallDir{ | |
| 46 | .custom = "static", | |
| 47 | }; | |
| 48 | static.install(); | |
| 49 | ||
| 50 | const dylib = b.addSharedLibrary("a", null, b.version(1, 0, 0)); | |
| 51 | dylib.setBuildMode(mode); | |
| 52 | dylib.addCSourceFile("a.c", &.{}); | |
| 53 | dylib.linkLibC(); | |
| 54 | dylib.override_dest_dir = std.build.InstallDir{ | |
| 55 | .custom = "dynamic", | |
| 56 | }; | |
| 57 | dylib.install(); | |
| 58 | ||
| 59 | const exe = b.addExecutable("main", null); | |
| 60 | exe.setBuildMode(mode); | |
| 61 | exe.addCSourceFile("main.c", &.{}); | |
| 62 | exe.linkSystemLibraryName("a"); | |
| 63 | exe.linkLibC(); | |
| 64 | exe.addLibraryPath(b.pathFromRoot("zig-out/static")); | |
| 65 | exe.addLibraryPath(b.pathFromRoot("zig-out/dynamic")); | |
| 66 | exe.addRPath(b.pathFromRoot("zig-out/dynamic")); | |
| 67 | return exe; | |
| 68 | } |
test/link/macho/search_strategy/main.c created+9| ... | ... | @@ -0,0 +1,9 @@ |
| 1 | #include <stdio.h> | |
| 2 | ||
| 3 | char* hello(); | |
| 4 | extern char world[]; | |
| 5 | ||
| 6 | int main() { | |
| 7 | printf("%s %s", hello(), world); | |
| 8 | return 0; | |
| 9 | } |