authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-02 14:05:51+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-02 22:00:16+01:00
log92deebcd668750bd4042c5874bf35b447828cd8a
tree412ac01bd1ee8c20bf4fc55281626e885e8fd0e4
parent9eda6ccefce370c76209ea50dd57fe65bfe25536

cli+build: handle -ObjC flag and route it to MachO linker


11 files changed, 91 insertions(+), 31 deletions(-)

lib/std/Build/Step/Compile.zig+6
......@@ -149,6 +149,9 @@ headerpad_max_install_names: bool = false,
149149/// (Darwin) Remove dylibs that are unreachable by the entry point or exported symbols.
150150dead_strip_dylibs: bool = false,
151151
152/// (Darwin) Force load all members of static archives that implement an Objective-C class or category
153force_load_objc: bool = false,
154
152155/// Position Independent Executable
153156pie: ?bool = null,
154157
......@@ -1433,6 +1436,9 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
14331436 if (self.dead_strip_dylibs) {
14341437 try zig_args.append("-dead_strip_dylibs");
14351438 }
1439 if (self.force_load_objc) {
1440 try zig_args.append("-ObjC");
1441 }
14361442
14371443 try addFlag(&zig_args, "compiler-rt", self.bundle_compiler_rt);
14381444 try addFlag(&zig_args, "dll-export-fns", self.dll_export_fns);
src/Compilation.zig+6-2
......@@ -1113,6 +1113,8 @@ pub const CreateOptions = struct {
11131113 headerpad_max_install_names: bool = false,
11141114 /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols
11151115 dead_strip_dylibs: bool = false,
1116 /// (Darwin) Force load all members of static archives that implement an Objective-C class or category
1117 force_load_objc: bool = false,
11161118 libcxx_abi_version: libcxx.AbiVersion = libcxx.AbiVersion.default,
11171119 /// (Windows) PDB source path prefix to instruct the linker how to resolve relative
11181120 /// paths when consolidating CodeView streams into a single PDB file.
......@@ -1591,6 +1593,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
15911593 .headerpad_size = options.headerpad_size,
15921594 .headerpad_max_install_names = options.headerpad_max_install_names,
15931595 .dead_strip_dylibs = options.dead_strip_dylibs,
1596 .force_load_objc = options.force_load_objc,
15941597 .pdb_source_path = options.pdb_source_path,
15951598 .pdb_out_path = options.pdb_out_path,
15961599 .entry_addr = null, // CLI does not expose this option (yet?)
......@@ -2456,7 +2459,7 @@ fn prepareWholeEmitSubPath(arena: Allocator, opt_emit: ?EmitLoc) error{OutOfMemo
24562459/// to remind the programmer to update multiple related pieces of code that
24572460/// are in different locations. Bump this number when adding or deleting
24582461/// anything from the link cache manifest.
2459pub const link_hash_implementation_version = 11;
2462pub const link_hash_implementation_version = 12;
24602463
24612464fn addNonIncrementalStuffToCacheManifest(
24622465 comp: *Compilation,
......@@ -2465,7 +2468,7 @@ fn addNonIncrementalStuffToCacheManifest(
24652468) !void {
24662469 const gpa = comp.gpa;
24672470
2468 comptime assert(link_hash_implementation_version == 11);
2471 comptime assert(link_hash_implementation_version == 12);
24692472
24702473 if (comp.module) |mod| {
24712474 try addModuleTableToCacheHash(gpa, arena, &man.hash, mod.root_mod, mod.main_mod, .{ .files = man });
......@@ -2589,6 +2592,7 @@ fn addNonIncrementalStuffToCacheManifest(
25892592 man.hash.addOptional(opts.headerpad_size);
25902593 man.hash.add(opts.headerpad_max_install_names);
25912594 man.hash.add(opts.dead_strip_dylibs);
2595 man.hash.add(opts.force_load_objc);
25922596
25932597 // COFF specific stuff
25942598 man.hash.addOptional(opts.subsystem);
src/clang_options_data.zig+8-1
......@@ -115,7 +115,14 @@ flagpd1("Mach"),
115115 .pd2 = false,
116116 .psl = false,
117117},
118flagpd1("ObjC"),
118.{
119 .name = "ObjC",
120 .syntax = .flag,
121 .zig_equivalent = .force_load_objc,
122 .pd1 = true,
123 .pd2 = false,
124 .psl = false,
125},
119126flagpd1("ObjC++"),
120127flagpd1("P"),
121128flagpd1("Q"),
src/link.zig+16-10
......@@ -136,30 +136,36 @@ pub const File = struct {
136136 framework_dirs: []const []const u8,
137137 rpath_list: []const []const u8,
138138
139 /// (Zig compiler development) Enable dumping of linker's state as JSON.
139 /// Zig compiler development linker flags.
140 /// Enable dumping of linker's state as JSON.
140141 enable_link_snapshots: bool,
141142
142 /// (Darwin) Install name for the dylib
143 /// Darwin-specific linker flags:
144 /// Install name for the dylib
143145 install_name: ?[]const u8,
144 /// (Darwin) Path to entitlements file
146 /// Path to entitlements file
145147 entitlements: ?[]const u8,
146 /// (Darwin) size of the __PAGEZERO segment
148 /// size of the __PAGEZERO segment
147149 pagezero_size: ?u64,
148 /// (Darwin) set minimum space for future expansion of the load commands
150 /// Set minimum space for future expansion of the load commands
149151 headerpad_size: ?u32,
150 /// (Darwin) set enough space as if all paths were MATPATHLEN
152 /// Set enough space as if all paths were MATPATHLEN
151153 headerpad_max_install_names: bool,
152 /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols
154 /// Remove dylibs that are unreachable by the entry point or exported symbols
153155 dead_strip_dylibs: bool,
154156 frameworks: []const MachO.Framework,
155157 darwin_sdk_layout: ?MachO.SdkLayout,
158 /// Force load all members of static archives that implement an
159 /// Objective-C class or category
160 force_load_objc: bool,
156161
157 /// (Windows) PDB source path prefix to instruct the linker how to resolve relative
162 /// Windows-specific linker flags:
163 /// PDB source path prefix to instruct the linker how to resolve relative
158164 /// paths when consolidating CodeView streams into a single PDB file.
159165 pdb_source_path: ?[]const u8,
160 /// (Windows) PDB output path
166 /// PDB output path
161167 pdb_out_path: ?[]const u8,
162 /// (Windows) .def file to specify when linking
168 /// .def file to specify when linking
163169 module_definition_file: ?[]const u8,
164170
165171 pub const Entry = union(enum) {
src/link/Coff/lld.zig+1-1
......@@ -70,7 +70,7 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node)
7070 man = comp.cache_parent.obtain();
7171 self.base.releaseLock();
7272
73 comptime assert(Compilation.link_hash_implementation_version == 11);
73 comptime assert(Compilation.link_hash_implementation_version == 12);
7474
7575 for (comp.objects) |obj| {
7676 _ = try man.addFile(obj.path, null);
src/link/Elf.zig+1-1
......@@ -2380,7 +2380,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) !voi
23802380 // We are about to obtain this lock, so here we give other processes a chance first.
23812381 self.base.releaseLock();
23822382
2383 comptime assert(Compilation.link_hash_implementation_version == 11);
2383 comptime assert(Compilation.link_hash_implementation_version == 12);
23842384
23852385 try man.addOptionalFile(self.linker_script);
23862386 try man.addOptionalFile(self.version_script);
src/link/MachO.zig+7-2
......@@ -217,6 +217,7 @@ pub fn createEmpty(
217217 .undefined_treatment = if (allow_shlib_undefined) .dynamic_lookup else .@"error",
218218 .lib_dirs = options.lib_dirs,
219219 .framework_dirs = options.framework_dirs,
220 .force_load_objc = options.force_load_objc,
220221 };
221222 if (use_llvm and comp.config.have_zcu) {
222223 self.llvm_object = try LlvmObject.create(arena, comp);
......@@ -807,6 +808,10 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
807808 try argv.append("-dead_strip_dylibs");
808809 }
809810
811 if (self.force_load_objc) {
812 try argv.append("-ObjC");
813 }
814
810815 if (self.entry_name) |entry_name| {
811816 try argv.appendSlice(&.{ "-e", entry_name });
812817 }
......@@ -1247,7 +1252,7 @@ fn parseDependentDylibs(self: *MachO) !void {
12471252 try checked_paths.append(rel_path);
12481253 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
12491254 const full_path = std.fs.realpath(rel_path, &buffer) catch continue;
1250 break :full_path full_path;
1255 break :full_path try arena.dupe(u8, full_path);
12511256 }
12521257 } else if (eatPrefix(id.name, "@loader_path/")) |_| {
12531258 try self.reportParseError2(dylib_index, "TODO handle install_name '{s}'", .{id.name});
......@@ -1260,7 +1265,7 @@ fn parseDependentDylibs(self: *MachO) !void {
12601265 try checked_paths.append(try arena.dupe(u8, id.name));
12611266 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
12621267 if (std.fs.realpath(id.name, &buffer)) |full_path| {
1263 break :full_path full_path;
1268 break :full_path try arena.dupe(u8, full_path);
12641269 } else |_| {
12651270 try self.reportMissingDependencyError(
12661271 self.getFile(dylib_index).?.dylib.getUmbrella(self).index,
src/link/Wasm.zig+2-2
......@@ -3511,7 +3511,7 @@ fn linkWithZld(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) lin
35113511 // We are about to obtain this lock, so here we give other processes a chance first.
35123512 wasm.base.releaseLock();
35133513
3514 comptime assert(Compilation.link_hash_implementation_version == 11);
3514 comptime assert(Compilation.link_hash_implementation_version == 12);
35153515
35163516 for (objects) |obj| {
35173517 _ = try man.addFile(obj.path, null);
......@@ -4580,7 +4580,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) !vo
45804580 // We are about to obtain this lock, so here we give other processes a chance first.
45814581 wasm.base.releaseLock();
45824582
4583 comptime assert(Compilation.link_hash_implementation_version == 11);
4583 comptime assert(Compilation.link_hash_implementation_version == 12);
45844584
45854585 for (comp.objects) |obj| {
45864586 _ = try man.addFile(obj.path, null);
src/main.zig+10-1
......@@ -559,6 +559,7 @@ const usage_build_generic =
559559 \\ -headerpad_max_install_names (Darwin) set enough space as if all paths were MAXPATHLEN
560560 \\ -dead_strip (Darwin) remove functions and data that are unreachable by the entry point or exported symbols
561561 \\ -dead_strip_dylibs (Darwin) remove dylibs that are unreachable by the entry point or exported symbols
562 \\ -ObjC (Darwin) force load all members of static archives that implement an Objective-C class or category
562563 \\ --import-memory (WebAssembly) import memory from the environment
563564 \\ --export-memory (WebAssembly) export memory to the host (Default unless --import-memory used)
564565 \\ --import-symbols (WebAssembly) import missing symbols from the host environment
......@@ -589,7 +590,7 @@ const usage_build_generic =
589590 \\ -rpath [path] Add directory to the runtime library search path
590591 \\ -framework [name] (Darwin) link against framework
591592 \\ -needed_framework [name] (Darwin) link against framework (even if unused)
592 \\ -needed_library [lib] link against system library (even if unused)
593 \\ -needed_library [lib] (Darwin) link against system library (even if unused)
593594 \\ -weak_framework [name] (Darwin) link against framework and mark it and all referenced symbols as weak
594595 \\ -F[dir] (Darwin) add search path for frameworks
595596 \\ --export=[value] (WebAssembly) Force a symbol to be exported
......@@ -889,6 +890,7 @@ fn buildOutputType(
889890 var headerpad_size: ?u32 = null;
890891 var headerpad_max_install_names: bool = false;
891892 var dead_strip_dylibs: bool = false;
893 var force_load_objc: bool = false;
892894 var contains_res_file: bool = false;
893895 var reference_trace: ?u32 = null;
894896 var pdb_out_path: ?[]const u8 = null;
......@@ -1182,6 +1184,8 @@ fn buildOutputType(
11821184 linker_gc_sections = true;
11831185 } else if (mem.eql(u8, arg, "-dead_strip_dylibs")) {
11841186 dead_strip_dylibs = true;
1187 } else if (mem.eql(u8, arg, "-ObjC")) {
1188 force_load_objc = true;
11851189 } else if (mem.eql(u8, arg, "-T") or mem.eql(u8, arg, "--script")) {
11861190 linker_script = args_iter.nextOrFatal();
11871191 } else if (mem.eql(u8, arg, "-version-script") or mem.eql(u8, arg, "--version-script")) {
......@@ -2061,6 +2065,7 @@ fn buildOutputType(
20612065 .force_undefined_symbol => {
20622066 try force_undefined_symbols.put(arena, it.only_arg, {});
20632067 },
2068 .force_load_objc => force_load_objc = true,
20642069 .weak_library => try create_module.system_libs.put(arena, it.only_arg, .{
20652070 .needed = false,
20662071 .weak = true,
......@@ -2167,6 +2172,8 @@ fn buildOutputType(
21672172 linker_gc_sections = true;
21682173 } else if (mem.eql(u8, arg, "-dead_strip_dylibs")) {
21692174 dead_strip_dylibs = true;
2175 } else if (mem.eql(u8, arg, "-ObjC")) {
2176 force_load_objc = true;
21702177 } else if (mem.eql(u8, arg, "--no-undefined")) {
21712178 linker_z_defs = true;
21722179 } else if (mem.eql(u8, arg, "--gc-sections")) {
......@@ -3246,6 +3253,7 @@ fn buildOutputType(
32463253 .headerpad_size = headerpad_size,
32473254 .headerpad_max_install_names = headerpad_max_install_names,
32483255 .dead_strip_dylibs = dead_strip_dylibs,
3256 .force_load_objc = force_load_objc,
32493257 .reference_trace = reference_trace,
32503258 .pdb_out_path = pdb_out_path,
32513259 .error_limit = error_limit,
......@@ -6266,6 +6274,7 @@ pub const ClangArgIterator = struct {
62666274 compress_debug_sections,
62676275 install_name,
62686276 undefined,
6277 force_load_objc,
62696278 };
62706279
62716280 const Args = struct {
test/link/macho.zig+30-11
......@@ -969,19 +969,38 @@ fn testObjc(b: *Build, opts: Options) *Step {
969969 \\@end
970970 });
971971
972 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
973 exe.root_module.linkSystemLibrary("a", .{});
974 exe.root_module.linkFramework("Foundation", .{});
975 exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
972 {
973 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
974 exe.root_module.linkSystemLibrary("a", .{});
975 exe.root_module.linkFramework("Foundation", .{});
976 exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
976977
977 const check = exe.checkObject();
978 check.checkInSymtab();
979 check.checkContains("_OBJC_");
980 test_step.dependOn(&check.step);
978 const check = exe.checkObject();
979 check.checkInSymtab();
980 check.checkNotPresent("_OBJC_");
981 test_step.dependOn(&check.step);
981982
982 const run = addRunArtifact(exe);
983 run.expectExitCode(0);
984 test_step.dependOn(&run.step);
983 const run = addRunArtifact(exe);
984 run.expectExitCode(0);
985 test_step.dependOn(&run.step);
986 }
987
988 {
989 const exe = addExecutable(b, opts, .{ .name = "main2", .c_source_bytes = "int main() { return 0; }" });
990 exe.root_module.linkSystemLibrary("a", .{});
991 exe.root_module.linkFramework("Foundation", .{});
992 exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
993 exe.force_load_objc = true;
994
995 const check = exe.checkObject();
996 check.checkInSymtab();
997 check.checkContains("_OBJC_");
998 test_step.dependOn(&check.step);
999
1000 const run = addRunArtifact(exe);
1001 run.expectExitCode(0);
1002 test_step.dependOn(&run.step);
1003 }
9851004
9861005 return test_step;
9871006}
tools/update_clang_options.zig+4
......@@ -528,6 +528,10 @@ const known_options = [_]KnownOpt{
528528 .name = "x",
529529 .ident = "x",
530530 },
531 .{
532 .name = "ObjC",
533 .ident = "force_load_objc",
534 },
531535};
532536
533537const blacklisted_options = [_][]const u8{};