| author | |
| committer | |
| log | efc5c97bff87d4c28ae9642fe69d9bc2c7e9eeb7 |
| tree | 12b31bae7ed111c1f62541c7d46f20ad6d222717 |
| parent | a76775b50a65fd0ea0fd17d6ef3c42058df13997 |
13 files changed, 94 insertions(+), 47 deletions(-)
lib/std/build.zig+6| ... | @@ -1601,6 +1601,9 @@ pub const LibExeObjStep = struct { | ... | @@ -1601,6 +1601,9 @@ pub const LibExeObjStep = struct { |
| 1601 | /// and start of `__TEXT,__text` section to a value fitting all paths expanded to MAXPATHLEN. | 1601 | /// and start of `__TEXT,__text` section to a value fitting all paths expanded to MAXPATHLEN. |
| 1602 | headerpad_max_install_names: bool = false, | 1602 | headerpad_max_install_names: bool = false, |
| 1603 | 1603 | ||
| 1604 | /// (Darwin) Remove dylibs that are unreachable by the entry point or exported symbols. | ||
| 1605 | dead_strip_dylibs: bool = false, | ||
| 1606 | |||
| 1604 | /// Position Independent Code | 1607 | /// Position Independent Code |
| 1605 | force_pic: ?bool = null, | 1608 | force_pic: ?bool = null, |
| 1606 | 1609 | ||
| ... | @@ -2676,6 +2679,9 @@ pub const LibExeObjStep = struct { | ... | @@ -2676,6 +2679,9 @@ pub const LibExeObjStep = struct { |
| 2676 | if (self.headerpad_max_install_names) { | 2679 | if (self.headerpad_max_install_names) { |
| 2677 | try zig_args.append("-headerpad_max_install_names"); | 2680 | try zig_args.append("-headerpad_max_install_names"); |
| 2678 | } | 2681 | } |
| 2682 | if (self.dead_strip_dylibs) { | ||
| 2683 | try zig_args.append("-dead_strip_dylibs"); | ||
| 2684 | } | ||
| 2679 | 2685 | ||
| 2680 | if (self.bundle_compiler_rt) |x| { | 2686 | if (self.bundle_compiler_rt) |x| { |
| 2681 | if (x) { | 2687 | if (x) { |
src/Compilation.zig+6-2| ... | @@ -911,6 +911,8 @@ pub const InitOptions = struct { | ... | @@ -911,6 +911,8 @@ pub const InitOptions = struct { |
| 911 | headerpad_size: ?u32 = null, | 911 | headerpad_size: ?u32 = null, |
| 912 | /// (Darwin) set enough space as if all paths were MATPATHLEN | 912 | /// (Darwin) set enough space as if all paths were MATPATHLEN |
| 913 | headerpad_max_install_names: bool = false, | 913 | headerpad_max_install_names: bool = false, |
| 914 | /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols | ||
| 915 | dead_strip_dylibs: bool = false, | ||
| 914 | }; | 916 | }; |
| 915 | 917 | ||
| 916 | fn addPackageTableToCacheHash( | 918 | fn addPackageTableToCacheHash( |
| ... | @@ -1754,6 +1756,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { | ... | @@ -1754,6 +1756,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1754 | .search_strategy = options.search_strategy, | 1756 | .search_strategy = options.search_strategy, |
| 1755 | .headerpad_size = options.headerpad_size, | 1757 | .headerpad_size = options.headerpad_size, |
| 1756 | .headerpad_max_install_names = options.headerpad_max_install_names, | 1758 | .headerpad_max_install_names = options.headerpad_max_install_names, |
| 1759 | .dead_strip_dylibs = options.dead_strip_dylibs, | ||
| 1757 | }); | 1760 | }); |
| 1758 | errdefer bin_file.destroy(); | 1761 | errdefer bin_file.destroy(); |
| 1759 | comp.* = .{ | 1762 | comp.* = .{ |
| ... | @@ -2369,7 +2372,7 @@ fn prepareWholeEmitSubPath(arena: Allocator, opt_emit: ?EmitLoc) error{OutOfMemo | ... | @@ -2369,7 +2372,7 @@ fn prepareWholeEmitSubPath(arena: Allocator, opt_emit: ?EmitLoc) error{OutOfMemo |
| 2369 | /// to remind the programmer to update multiple related pieces of code that | 2372 | /// to remind the programmer to update multiple related pieces of code that |
| 2370 | /// are in different locations. Bump this number when adding or deleting | 2373 | /// are in different locations. Bump this number when adding or deleting |
| 2371 | /// anything from the link cache manifest. | 2374 | /// anything from the link cache manifest. |
| 2372 | pub const link_hash_implementation_version = 6; | 2375 | pub const link_hash_implementation_version = 7; |
| 2373 | 2376 | ||
| 2374 | fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void { | 2377 | fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void { |
| 2375 | const gpa = comp.gpa; | 2378 | const gpa = comp.gpa; |
| ... | @@ -2379,7 +2382,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes | ... | @@ -2379,7 +2382,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes |
| 2379 | defer arena_allocator.deinit(); | 2382 | defer arena_allocator.deinit(); |
| 2380 | const arena = arena_allocator.allocator(); | 2383 | const arena = arena_allocator.allocator(); |
| 2381 | 2384 | ||
| 2382 | comptime assert(link_hash_implementation_version == 6); | 2385 | comptime assert(link_hash_implementation_version == 7); |
| 2383 | 2386 | ||
| 2384 | if (comp.bin_file.options.module) |mod| { | 2387 | if (comp.bin_file.options.module) |mod| { |
| 2385 | const main_zig_file = try mod.main_pkg.root_src_directory.join(arena, &[_][]const u8{ | 2388 | const main_zig_file = try mod.main_pkg.root_src_directory.join(arena, &[_][]const u8{ |
| ... | @@ -2488,6 +2491,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes | ... | @@ -2488,6 +2491,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes |
| 2488 | man.hash.addOptional(comp.bin_file.options.search_strategy); | 2491 | man.hash.addOptional(comp.bin_file.options.search_strategy); |
| 2489 | man.hash.addOptional(comp.bin_file.options.headerpad_size); | 2492 | man.hash.addOptional(comp.bin_file.options.headerpad_size); |
| 2490 | man.hash.add(comp.bin_file.options.headerpad_max_install_names); | 2493 | man.hash.add(comp.bin_file.options.headerpad_max_install_names); |
| 2494 | man.hash.add(comp.bin_file.options.dead_strip_dylibs); | ||
| 2491 | 2495 | ||
| 2492 | // COFF specific stuff | 2496 | // COFF specific stuff |
| 2493 | man.hash.addOptional(comp.bin_file.options.subsystem); | 2497 | man.hash.addOptional(comp.bin_file.options.subsystem); |
src/link.zig+3| ... | @@ -199,6 +199,9 @@ pub const Options = struct { | ... | @@ -199,6 +199,9 @@ pub const Options = struct { |
| 199 | /// (Darwin) set enough space as if all paths were MATPATHLEN | 199 | /// (Darwin) set enough space as if all paths were MATPATHLEN |
| 200 | headerpad_max_install_names: bool = false, | 200 | headerpad_max_install_names: bool = false, |
| 201 | 201 | ||
| 202 | /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols | ||
| 203 | dead_strip_dylibs: bool = false, | ||
| 204 | |||
| 202 | pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode { | 205 | pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode { |
| 203 | return if (options.use_lld) .Obj else options.output_mode; | 206 | return if (options.use_lld) .Obj else options.output_mode; |
| 204 | } | 207 | } |
src/link/Coff.zig+1-1| ... | @@ -969,7 +969,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) ! | ... | @@ -969,7 +969,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) ! |
| 969 | man = comp.cache_parent.obtain(); | 969 | man = comp.cache_parent.obtain(); |
| 970 | self.base.releaseLock(); | 970 | self.base.releaseLock(); |
| 971 | 971 | ||
| 972 | comptime assert(Compilation.link_hash_implementation_version == 6); | 972 | comptime assert(Compilation.link_hash_implementation_version == 7); |
| 973 | 973 | ||
| 974 | for (self.base.options.objects) |obj| { | 974 | for (self.base.options.objects) |obj| { |
| 975 | _ = try man.addFile(obj.path, null); | 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,7 +1298,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v |
| 1298 | // We are about to obtain this lock, so here we give other processes a chance first. | 1298 | // We are about to obtain this lock, so here we give other processes a chance first. |
| 1299 | self.base.releaseLock(); | 1299 | self.base.releaseLock(); |
| 1300 | 1300 | ||
| 1301 | comptime assert(Compilation.link_hash_implementation_version == 6); | 1301 | comptime assert(Compilation.link_hash_implementation_version == 7); |
| 1302 | 1302 | ||
| 1303 | try man.addOptionalFile(self.base.options.linker_script); | 1303 | try man.addOptionalFile(self.base.options.linker_script); |
| 1304 | try man.addOptionalFile(self.base.options.version_script); | 1304 | try man.addOptionalFile(self.base.options.version_script); |
src/link/MachO.zig+12-2| ... | @@ -541,7 +541,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -541,7 +541,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 541 | // We are about to obtain this lock, so here we give other processes a chance first. | 541 | // We are about to obtain this lock, so here we give other processes a chance first. |
| 542 | self.base.releaseLock(); | 542 | self.base.releaseLock(); |
| 543 | 543 | ||
| 544 | comptime assert(Compilation.link_hash_implementation_version == 6); | 544 | comptime assert(Compilation.link_hash_implementation_version == 7); |
| 545 | 545 | ||
| 546 | for (self.base.options.objects) |obj| { | 546 | for (self.base.options.objects) |obj| { |
| 547 | _ = try man.addFile(obj.path, null); | 547 | _ = try man.addFile(obj.path, null); |
| ... | @@ -558,6 +558,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -558,6 +558,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 558 | man.hash.addOptional(self.base.options.search_strategy); | 558 | man.hash.addOptional(self.base.options.search_strategy); |
| 559 | man.hash.addOptional(self.base.options.headerpad_size); | 559 | man.hash.addOptional(self.base.options.headerpad_size); |
| 560 | man.hash.add(self.base.options.headerpad_max_install_names); | 560 | man.hash.add(self.base.options.headerpad_max_install_names); |
| 561 | man.hash.add(self.base.options.dead_strip_dylibs); | ||
| 561 | man.hash.addListOfBytes(self.base.options.lib_dirs); | 562 | man.hash.addListOfBytes(self.base.options.lib_dirs); |
| 562 | man.hash.addListOfBytes(self.base.options.framework_dirs); | 563 | man.hash.addListOfBytes(self.base.options.framework_dirs); |
| 563 | man.hash.addListOfBytes(self.base.options.frameworks); | 564 | man.hash.addListOfBytes(self.base.options.frameworks); |
| ... | @@ -987,6 +988,10 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -987,6 +988,10 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 987 | try argv.append("-headerpad_max_install_names"); | 988 | try argv.append("-headerpad_max_install_names"); |
| 988 | } | 989 | } |
| 989 | 990 | ||
| 991 | if (self.base.options.dead_strip_dylibs) { | ||
| 992 | try argv.append("-dead_strip_dylibs"); | ||
| 993 | } | ||
| 994 | |||
| 990 | if (self.base.options.entry) |entry| { | 995 | if (self.base.options.entry) |entry| { |
| 991 | try argv.append("-e"); | 996 | try argv.append("-e"); |
| 992 | try argv.append(entry); | 997 | try argv.append(entry); |
| ... | @@ -1425,7 +1430,12 @@ pub fn parseDylib(self: *MachO, path: []const u8, opts: DylibCreateOpts) ParseDy | ... | @@ -1425,7 +1430,12 @@ pub fn parseDylib(self: *MachO, path: []const u8, opts: DylibCreateOpts) ParseDy |
| 1425 | try self.dylibs.append(self.base.allocator, dylib); | 1430 | try self.dylibs.append(self.base.allocator, dylib); |
| 1426 | try self.dylibs_map.putNoClobber(self.base.allocator, dylib.id.?.name, dylib_id); | 1431 | try self.dylibs_map.putNoClobber(self.base.allocator, dylib.id.?.name, dylib_id); |
| 1427 | 1432 | ||
| 1428 | if (!(opts.is_dependent or self.referenced_dylibs.contains(dylib_id))) { | 1433 | const should_link_dylib_even_if_unreachable = blk: { |
| 1434 | if (self.base.options.dead_strip_dylibs) break :blk false; | ||
| 1435 | break :blk !(opts.is_dependent or self.referenced_dylibs.contains(dylib_id)); | ||
| 1436 | }; | ||
| 1437 | |||
| 1438 | if (should_link_dylib_even_if_unreachable) { | ||
| 1429 | try self.addLoadDylibLC(dylib_id); | 1439 | try self.addLoadDylibLC(dylib_id); |
| 1430 | try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {}); | 1440 | try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {}); |
| 1431 | } | 1441 | } |
src/link/Wasm.zig+1-1| ... | @@ -2546,7 +2546,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! | ... | @@ -2546,7 +2546,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! |
| 2546 | // We are about to obtain this lock, so here we give other processes a chance first. | 2546 | // We are about to obtain this lock, so here we give other processes a chance first. |
| 2547 | self.base.releaseLock(); | 2547 | self.base.releaseLock(); |
| 2548 | 2548 | ||
| 2549 | comptime assert(Compilation.link_hash_implementation_version == 6); | 2549 | comptime assert(Compilation.link_hash_implementation_version == 7); |
| 2550 | 2550 | ||
| 2551 | for (self.base.options.objects) |obj| { | 2551 | for (self.base.options.objects) |obj| { |
| 2552 | _ = try man.addFile(obj.path, null); | 2552 | _ = try man.addFile(obj.path, null); |
src/main.zig+7| ... | @@ -452,6 +452,7 @@ const usage_build_generic = | ... | @@ -452,6 +452,7 @@ const usage_build_generic = |
| 452 | \\ -search_dylibs_first (Darwin) search `libx.dylib` in each dir in library search paths, then `libx.a` | 452 | \\ -search_dylibs_first (Darwin) search `libx.dylib` in each dir in library search paths, then `libx.a` |
| 453 | \\ -headerpad [value] (Darwin) set minimum space for future expansion of the load commands in hexadecimal notation | 453 | \\ -headerpad [value] (Darwin) set minimum space for future expansion of the load commands in hexadecimal notation |
| 454 | \\ -headerpad_max_install_names (Darwin) set enough space as if all paths were MAXPATHLEN | 454 | \\ -headerpad_max_install_names (Darwin) set enough space as if all paths were MAXPATHLEN |
| 455 | \\ -dead_strip_dylibs (Darwin) remove dylibs that are unreachable by the entry point or exported symbols | ||
| 455 | \\ --import-memory (WebAssembly) import memory from the environment | 456 | \\ --import-memory (WebAssembly) import memory from the environment |
| 456 | \\ --import-table (WebAssembly) import function table from the host environment | 457 | \\ --import-table (WebAssembly) import function table from the host environment |
| 457 | \\ --export-table (WebAssembly) export function table to the host environment | 458 | \\ --export-table (WebAssembly) export function table to the host environment |
| ... | @@ -703,6 +704,7 @@ fn buildOutputType( | ... | @@ -703,6 +704,7 @@ fn buildOutputType( |
| 703 | var search_strategy: ?link.File.MachO.SearchStrategy = null; | 704 | var search_strategy: ?link.File.MachO.SearchStrategy = null; |
| 704 | var headerpad_size: ?u32 = null; | 705 | var headerpad_size: ?u32 = null; |
| 705 | var headerpad_max_install_names: bool = false; | 706 | var headerpad_max_install_names: bool = false; |
| 707 | var dead_strip_dylibs: bool = false; | ||
| 706 | 708 | ||
| 707 | // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names. | 709 | // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names. |
| 708 | // This array is populated by zig cc frontend and then has to be converted to zig-style | 710 | // This array is populated by zig cc frontend and then has to be converted to zig-style |
| ... | @@ -937,6 +939,8 @@ fn buildOutputType( | ... | @@ -937,6 +939,8 @@ fn buildOutputType( |
| 937 | }; | 939 | }; |
| 938 | } else if (mem.eql(u8, arg, "-headerpad_max_install_names")) { | 940 | } else if (mem.eql(u8, arg, "-headerpad_max_install_names")) { |
| 939 | headerpad_max_install_names = true; | 941 | headerpad_max_install_names = true; |
| 942 | } else if (mem.eql(u8, arg, "-dead_strip_dylibs")) { | ||
| 943 | dead_strip_dylibs = true; | ||
| 940 | } else if (mem.eql(u8, arg, "-T") or mem.eql(u8, arg, "--script")) { | 944 | } else if (mem.eql(u8, arg, "-T") or mem.eql(u8, arg, "--script")) { |
| 941 | linker_script = args_iter.next() orelse { | 945 | linker_script = args_iter.next() orelse { |
| 942 | fatal("expected parameter after {s}", .{arg}); | 946 | fatal("expected parameter after {s}", .{arg}); |
| ... | @@ -1700,6 +1704,8 @@ fn buildOutputType( | ... | @@ -1700,6 +1704,8 @@ fn buildOutputType( |
| 1700 | }; | 1704 | }; |
| 1701 | } else if (mem.eql(u8, arg, "-headerpad_max_install_names")) { | 1705 | } else if (mem.eql(u8, arg, "-headerpad_max_install_names")) { |
| 1702 | headerpad_max_install_names = true; | 1706 | headerpad_max_install_names = true; |
| 1707 | } else if (mem.eql(u8, arg, "-dead_strip_dylibs")) { | ||
| 1708 | dead_strip_dylibs = true; | ||
| 1703 | } else if (mem.eql(u8, arg, "--gc-sections")) { | 1709 | } else if (mem.eql(u8, arg, "--gc-sections")) { |
| 1704 | linker_gc_sections = true; | 1710 | linker_gc_sections = true; |
| 1705 | } else if (mem.eql(u8, arg, "--no-gc-sections")) { | 1711 | } else if (mem.eql(u8, arg, "--no-gc-sections")) { |
| ... | @@ -2821,6 +2827,7 @@ fn buildOutputType( | ... | @@ -2821,6 +2827,7 @@ fn buildOutputType( |
| 2821 | .search_strategy = search_strategy, | 2827 | .search_strategy = search_strategy, |
| 2822 | .headerpad_size = headerpad_size, | 2828 | .headerpad_size = headerpad_size, |
| 2823 | .headerpad_max_install_names = headerpad_max_install_names, | 2829 | .headerpad_max_install_names = headerpad_max_install_names, |
| 2830 | .dead_strip_dylibs = dead_strip_dylibs, | ||
| 2824 | }) catch |err| switch (err) { | 2831 | }) catch |err| switch (err) { |
| 2825 | error.LibCUnavailable => { | 2832 | error.LibCUnavailable => { |
| 2826 | const target = target_info.target; | 2833 | const target = target_info.target; |
test/link.zig+1-1| ... | @@ -40,7 +40,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void { | ... | @@ -40,7 +40,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 40 | .build_modes = true, | 40 | .build_modes = true, |
| 41 | }); | 41 | }); |
| 42 | 42 | ||
| 43 | cases.addBuildFile("test/link/macho/frameworks/build.zig", .{ | 43 | cases.addBuildFile("test/link/macho/dead_strip_dylibs/build.zig", .{ |
| 44 | .build_modes = true, | 44 | .build_modes = true, |
| 45 | .requires_macos_sdk = true, | 45 | .requires_macos_sdk = true, |
| 46 | }); | 46 | }); |
test/link/macho/dead_strip_dylibs/build.zig created+46| ... | @@ -0,0 +1,46 @@ | ||
| 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 the program"); | ||
| 9 | |||
| 10 | { | ||
| 11 | // Without -dead_strip_dylibs we expect `-la` to include liba.dylib in the final executable | ||
| 12 | const exe = createScenario(b, mode); | ||
| 13 | |||
| 14 | const check = exe.checkObject(.macho); | ||
| 15 | check.checkStart("cmd LOAD_DYLIB"); | ||
| 16 | check.checkNext("name {*}Cocoa"); | ||
| 17 | |||
| 18 | check.checkStart("cmd LOAD_DYLIB"); | ||
| 19 | check.checkNext("name {*}libobjc{*}.dylib"); | ||
| 20 | |||
| 21 | test_step.dependOn(&check.step); | ||
| 22 | |||
| 23 | const run_cmd = exe.run(); | ||
| 24 | test_step.dependOn(&run_cmd.step); | ||
| 25 | } | ||
| 26 | |||
| 27 | { | ||
| 28 | // With -dead_strip_dylibs, we should include liba.dylib as it's unreachable | ||
| 29 | const exe = createScenario(b, mode); | ||
| 30 | exe.dead_strip_dylibs = true; | ||
| 31 | |||
| 32 | const run_cmd = exe.run(); | ||
| 33 | run_cmd.expected_exit_code = @bitCast(u8, @as(i8, -2)); // should fail | ||
| 34 | test_step.dependOn(&run_cmd.step); | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | fn createScenario(b: *Builder, mode: std.builtin.Mode) *LibExeObjectStep { | ||
| 39 | const exe = b.addExecutable("test", null); | ||
| 40 | b.default_step.dependOn(&exe.step); | ||
| 41 | exe.addCSourceFile("main.c", &[0][]const u8{}); | ||
| 42 | exe.setBuildMode(mode); | ||
| 43 | exe.linkLibC(); | ||
| 44 | exe.linkFramework("Cocoa"); | ||
| 45 | return exe; | ||
| 46 | } | ||
test/link/macho/dead_strip_dylibs/main.c created+10| ... | @@ -0,0 +1,10 @@ | ||
| 1 | #include <objc/runtime.h> | ||
| 2 | |||
| 3 | int main() { | ||
| 4 | if (objc_getClass("NSObject") == 0) { | ||
| 5 | return -1; | ||
| 6 | } | ||
| 7 | if (objc_getClass("NSApplication") == 0) { | ||
| 8 | return -2; | ||
| 9 | } | ||
| 10 | } | ||
test/link/macho/frameworks/build.zig deleted-32| ... | @@ -1,32 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const Builder = std.build.Builder; | ||
| 3 | |||
| 4 | pub fn build(b: *Builder) void { | ||
| 5 | const mode = b.standardReleaseOptions(); | ||
| 6 | |||
| 7 | const test_step = b.step("test", "Test the program"); | ||
| 8 | |||
| 9 | const exe = b.addExecutable("test", null); | ||
| 10 | b.default_step.dependOn(&exe.step); | ||
| 11 | exe.addCSourceFile("main.c", &[0][]const u8{}); | ||
| 12 | exe.setBuildMode(mode); | ||
| 13 | exe.linkLibC(); | ||
| 14 | exe.linkFramework("Cocoa"); | ||
| 15 | |||
| 16 | const check = exe.checkObject(.macho); | ||
| 17 | check.checkStart("cmd LOAD_DYLIB"); | ||
| 18 | check.checkNext("name {*}Cocoa"); | ||
| 19 | |||
| 20 | switch (mode) { | ||
| 21 | .Debug, .ReleaseSafe => { | ||
| 22 | check.checkStart("cmd LOAD_DYLIB"); | ||
| 23 | check.checkNext("name {*}libobjc{*}.dylib"); | ||
| 24 | }, | ||
| 25 | else => {}, | ||
| 26 | } | ||
| 27 | |||
| 28 | test_step.dependOn(&check.step); | ||
| 29 | |||
| 30 | const run_cmd = exe.run(); | ||
| 31 | test_step.dependOn(&run_cmd.step); | ||
| 32 | } | ||
test/link/macho/frameworks/main.c deleted-7| ... | @@ -1,7 +0,0 @@ | ||
| 1 | #include <assert.h> | ||
| 2 | #include <objc/runtime.h> | ||
| 3 | |||
| 4 | int main() { | ||
| 5 | assert(objc_getClass("NSObject") > 0); | ||
| 6 | assert(objc_getClass("NSApplication") > 0); | ||
| 7 | } | ||