authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-29 00:26:18-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-29 00:26:18-07:00
logfa6d150441d1d8679a77c5e9a6071fa952851376
treeaddec8faed4b228955e4e0a9f095d582f40625e2
parent41f6627521f7ff03962ff73944f5be3722346385

stage2: MachO LLD Linking


4 files changed, 385 insertions(+), 17 deletions(-)

BRANCH_TODO-1
...@@ -1,4 +1,3 @@...@@ -1,4 +1,3 @@
1 * MachO LLD linking
2 * audit the CLI options for stage21 * audit the CLI options for stage2
3 * audit the base cache hash2 * audit the base cache hash
4 * On operating systems that support it, do an execve for `zig test` and `zig run` rather than child process.3 * On operating systems that support it, do an execve for `zig test` and `zig run` rather than child process.
src/Compilation.zig+8-5
...@@ -558,6 +558,8 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -558,6 +558,8 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
558 break :blk buf.items[0 .. buf.items.len - 1 :0].ptr;558 break :blk buf.items[0 .. buf.items.len - 1 :0].ptr;
559 } else null;559 } else null;
560560
561 const strip = options.strip or !target_util.hasDebugInfo(options.target);
562
561 // We put everything into the cache hash that *cannot be modified during an incremental update*.563 // We put everything into the cache hash that *cannot be modified during an incremental update*.
562 // For example, one cannot change the target between updates, but one can change source files,564 // For example, one cannot change the target between updates, but one can change source files,
563 // so the target goes into the cache hash, but source files do not. This is so that we can565 // so the target goes into the cache hash, but source files do not. This is so that we can
...@@ -586,7 +588,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -586,7 +588,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
586 cache.hash.add(stack_check);588 cache.hash.add(stack_check);
587 cache.hash.add(link_mode);589 cache.hash.add(link_mode);
588 cache.hash.add(function_sections);590 cache.hash.add(function_sections);
589 cache.hash.add(options.strip);591 cache.hash.add(strip);
590 cache.hash.add(link_libc);592 cache.hash.add(link_libc);
591 cache.hash.add(options.link_libcpp);593 cache.hash.add(options.link_libcpp);
592 cache.hash.add(options.output_mode);594 cache.hash.add(options.output_mode);
...@@ -671,7 +673,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -671,7 +673,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
671 } else null;673 } else null;
672 errdefer if (module) |zm| zm.deinit();674 errdefer if (module) |zm| zm.deinit();
673675
674 const error_return_tracing = !options.strip and switch (options.optimize_mode) {676 const error_return_tracing = !strip and switch (options.optimize_mode) {
675 .Debug, .ReleaseSafe => true,677 .Debug, .ReleaseSafe => true,
676 .ReleaseFast, .ReleaseSmall => false,678 .ReleaseFast, .ReleaseSmall => false,
677 };679 };
...@@ -751,7 +753,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -751,7 +753,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
751 .system_libs = system_libs,753 .system_libs = system_libs,
752 .lib_dirs = options.lib_dirs,754 .lib_dirs = options.lib_dirs,
753 .rpath_list = options.rpath_list,755 .rpath_list = options.rpath_list,
754 .strip = options.strip,756 .strip = strip,
755 .is_native_os = options.is_native_os,757 .is_native_os = options.is_native_os,
756 .function_sections = options.function_sections orelse false,758 .function_sections = options.function_sections orelse false,
757 .allow_shlib_undefined = options.linker_allow_shlib_undefined,759 .allow_shlib_undefined = options.linker_allow_shlib_undefined,
...@@ -2415,10 +2417,11 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR...@@ -2415,10 +2417,11 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR
2415 };2417 };
2416 const root_name = mem.split(src_basename, ".").next().?;2418 const root_name = mem.split(src_basename, ".").next().?;
2417 const target = comp.getTarget();2419 const target = comp.getTarget();
2420 const output_mode: std.builtin.OutputMode = if (target.cpu.arch.isWasm()) .Obj else .Lib;
2418 const bin_basename = try std.zig.binNameAlloc(comp.gpa, .{2421 const bin_basename = try std.zig.binNameAlloc(comp.gpa, .{
2419 .root_name = root_name,2422 .root_name = root_name,
2420 .target = target,2423 .target = target,
2421 .output_mode = .Obj,2424 .output_mode = output_mode,
2422 });2425 });
2423 defer comp.gpa.free(bin_basename);2426 defer comp.gpa.free(bin_basename);
24242427
...@@ -2441,7 +2444,7 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR...@@ -2441,7 +2444,7 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR
2441 .target = target,2444 .target = target,
2442 .root_name = root_name,2445 .root_name = root_name,
2443 .root_pkg = &root_pkg,2446 .root_pkg = &root_pkg,
2444 .output_mode = .Obj,2447 .output_mode = output_mode,
2445 .rand = comp.rand,2448 .rand = comp.rand,
2446 .libc_installation = comp.bin_file.options.libc_installation,2449 .libc_installation = comp.bin_file.options.libc_installation,
2447 .emit_bin = emit_bin,2450 .emit_bin = emit_bin,
src/link/Elf.zig+8-10
...@@ -1241,6 +1241,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1241,6 +1241,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1241 break :blk full_obj_path;1241 break :blk full_obj_path;
1242 } else null;1242 } else null;
12431243
1244 const is_obj = self.base.options.output_mode == .Obj;
1244 const is_lib = self.base.options.output_mode == .Lib;1245 const is_lib = self.base.options.output_mode == .Lib;
1245 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;1246 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;
1246 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;1247 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
...@@ -1248,6 +1249,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1248,6 +1249,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1248 self.base.options.link_mode == .Dynamic and is_exe_or_dyn_lib;1249 self.base.options.link_mode == .Dynamic and is_exe_or_dyn_lib;
1249 const link_in_crt = self.base.options.link_libc and self.base.options.output_mode == .Exe;1250 const link_in_crt = self.base.options.link_libc and self.base.options.output_mode == .Exe;
1250 const target = self.base.options.target;1251 const target = self.base.options.target;
1252 const gc_sections = self.base.options.gc_sections orelse !is_obj;
1253 const stack_size = self.base.options.stack_size_override orelse 16777216;
1254 const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;
12511255
1252 // Here we want to determine whether we can save time by not invoking LLD when the1256 // Here we want to determine whether we can save time by not invoking LLD when the
1253 // output is unchanged. None of the linker options or the object files that are being1257 // output is unchanged. None of the linker options or the object files that are being
...@@ -1279,8 +1283,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1279,8 +1283,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1279 try man.addOptionalFile(module_obj_path);1283 try man.addOptionalFile(module_obj_path);
1280 // We can skip hashing libc and libc++ components that we are in charge of building from Zig1284 // We can skip hashing libc and libc++ components that we are in charge of building from Zig
1281 // installation sources because they are always a product of the compiler version + target information.1285 // installation sources because they are always a product of the compiler version + target information.
1282 man.hash.addOptional(self.base.options.stack_size_override);1286 man.hash.add(stack_size);
1283 man.hash.addOptional(self.base.options.gc_sections);1287 man.hash.add(gc_sections);
1284 man.hash.add(self.base.options.eh_frame_hdr);1288 man.hash.add(self.base.options.eh_frame_hdr);
1285 man.hash.add(self.base.options.rdynamic);1289 man.hash.add(self.base.options.rdynamic);
1286 man.hash.addListOfBytes(self.base.options.extra_lld_args);1290 man.hash.addListOfBytes(self.base.options.extra_lld_args);
...@@ -1304,7 +1308,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1304,7 +1308,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1304 man.hash.addOptional(self.base.options.version);1308 man.hash.addOptional(self.base.options.version);
1305 }1309 }
1306 man.hash.addStringSet(self.base.options.system_libs);1310 man.hash.addStringSet(self.base.options.system_libs);
1307 man.hash.addOptional(self.base.options.allow_shlib_undefined);1311 man.hash.add(allow_shlib_undefined);
1308 man.hash.add(self.base.options.bind_global_refs_locally);1312 man.hash.add(self.base.options.bind_global_refs_locally);
13091313
1310 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.1314 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
...@@ -1332,8 +1336,6 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1332,8 +1336,6 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1332 };1336 };
1333 }1337 }
13341338
1335 const is_obj = self.base.options.output_mode == .Obj;
1336
1337 // Create an LLD command line and invoke it.1339 // Create an LLD command line and invoke it.
1338 var argv = std.ArrayList([]const u8).init(self.base.allocator);1340 var argv = std.ArrayList([]const u8).init(self.base.allocator);
1339 defer argv.deinit();1341 defer argv.deinit();
...@@ -1347,9 +1349,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1347,9 +1349,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
13471349
1348 if (self.base.options.output_mode == .Exe) {1350 if (self.base.options.output_mode == .Exe) {
1349 try argv.append("-z");1351 try argv.append("-z");
1350 const stack_size = self.base.options.stack_size_override orelse 16777216;1352 try argv.append(try std.fmt.allocPrint(arena, "stack-size={}", .{stack_size}));
1351 const arg = try std.fmt.allocPrint(arena, "stack-size={}", .{stack_size});
1352 try argv.append(arg);
1353 }1353 }
13541354
1355 if (self.base.options.linker_script) |linker_script| {1355 if (self.base.options.linker_script) |linker_script| {
...@@ -1357,7 +1357,6 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1357,7 +1357,6 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1357 try argv.append(linker_script);1357 try argv.append(linker_script);
1358 }1358 }
13591359
1360 const gc_sections = self.base.options.gc_sections orelse !is_obj;
1361 if (gc_sections) {1360 if (gc_sections) {
1362 try argv.append("--gc-sections");1361 try argv.append("--gc-sections");
1363 }1362 }
...@@ -1577,7 +1576,6 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1577,7 +1576,6 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1577 }1576 }
1578 }1577 }
15791578
1580 const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;
1581 if (allow_shlib_undefined) {1579 if (allow_shlib_undefined) {
1582 try argv.append("--allow-shlib-undefined");1580 try argv.append("--allow-shlib-undefined");
1583 }1581 }
src/link/MachO.zig+369-1
...@@ -17,6 +17,8 @@ const Module = @import("../Module.zig");...@@ -17,6 +17,8 @@ const Module = @import("../Module.zig");
17const Compilation = @import("../Compilation.zig");17const Compilation = @import("../Compilation.zig");
18const link = @import("../link.zig");18const link = @import("../link.zig");
19const File = link.File;19const File = link.File;
20const Cache = @import("../Cache.zig");
21const target_util = @import("../target.zig");
2022
21pub const base_tag: File.Tag = File.Tag.macho;23pub const base_tag: File.Tag = File.Tag.macho;
2224
...@@ -180,8 +182,12 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*MachO {...@@ -180,8 +182,12 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*MachO {
180182
181pub fn flush(self: *MachO, comp: *Compilation) !void {183pub fn flush(self: *MachO, comp: *Compilation) !void {
182 if (build_options.have_llvm and self.base.options.use_lld) {184 if (build_options.have_llvm and self.base.options.use_lld) {
183 return error.MachOLLDLinkingUnimplemented;185 return self.linkWithLLD(comp);
184 } else {186 } else {
187 switch (self.base.options.effectiveOutputMode()) {
188 .Exe, .Obj => {},
189 .Lib => return error.TODOImplementWritingLibFiles,
190 }
185 return self.flushModule(comp);191 return self.flushModule(comp);
186 }192 }
187}193}
...@@ -282,6 +288,368 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -282,6 +288,368 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
282 }288 }
283}289}
284290
291fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
292 const tracy = trace(@src());
293 defer tracy.end();
294
295 var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);
296 defer arena_allocator.deinit();
297 const arena = &arena_allocator.allocator;
298
299 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.
300
301 // If there is no Zig code to compile, then we should skip flushing the output file because it
302 // will not be part of the linker line anyway.
303 const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: {
304 const use_stage1 = build_options.is_stage1 and self.base.options.use_llvm;
305 if (use_stage1) {
306 const obj_basename = try std.zig.binNameAlloc(arena, .{
307 .root_name = self.base.options.root_name,
308 .target = self.base.options.target,
309 .output_mode = .Obj,
310 });
311 const o_directory = self.base.options.module.?.zig_cache_artifact_directory;
312 const full_obj_path = try o_directory.join(arena, &[_][]const u8{obj_basename});
313 break :blk full_obj_path;
314 }
315
316 try self.flushModule(comp);
317 const obj_basename = self.base.intermediary_basename.?;
318 const full_obj_path = try directory.join(arena, &[_][]const u8{obj_basename});
319 break :blk full_obj_path;
320 } else null;
321
322 const is_obj = self.base.options.output_mode == .Obj;
323 const is_lib = self.base.options.output_mode == .Lib;
324 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;
325 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
326 const have_dynamic_linker = self.base.options.link_libc and
327 self.base.options.link_mode == .Dynamic and is_exe_or_dyn_lib;
328 const link_in_crt = self.base.options.link_libc and self.base.options.output_mode == .Exe;
329 const target = self.base.options.target;
330 const stack_size = self.base.options.stack_size_override orelse 16777216;
331 const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;
332
333 const id_symlink_basename = "lld.id";
334
335 var man: Cache.Manifest = undefined;
336 defer if (!self.base.options.disable_lld_caching) man.deinit();
337
338 var digest: [Cache.hex_digest_len]u8 = undefined;
339
340 if (!self.base.options.disable_lld_caching) {
341 man = comp.cache_parent.obtain();
342
343 // We are about to obtain this lock, so here we give other processes a chance first.
344 self.base.releaseLock();
345
346 try man.addOptionalFile(self.base.options.linker_script);
347 try man.addOptionalFile(self.base.options.version_script);
348 try man.addListOfFiles(self.base.options.objects);
349 for (comp.c_object_table.items()) |entry| {
350 _ = try man.addFile(entry.key.status.success.object_path, null);
351 }
352 try man.addOptionalFile(module_obj_path);
353 // We can skip hashing libc and libc++ components that we are in charge of building from Zig
354 // installation sources because they are always a product of the compiler version + target information.
355 man.hash.add(stack_size);
356 man.hash.add(self.base.options.rdynamic);
357 man.hash.addListOfBytes(self.base.options.extra_lld_args);
358 man.hash.addListOfBytes(self.base.options.lib_dirs);
359 man.hash.addListOfBytes(self.base.options.framework_dirs);
360 man.hash.addListOfBytes(self.base.options.frameworks);
361 man.hash.addListOfBytes(self.base.options.rpath_list);
362 man.hash.add(self.base.options.is_compiler_rt_or_libc);
363 man.hash.add(self.base.options.z_nodelete);
364 man.hash.add(self.base.options.z_defs);
365 if (is_dyn_lib) {
366 man.hash.addOptional(self.base.options.version);
367 }
368 man.hash.addStringSet(self.base.options.system_libs);
369 man.hash.add(allow_shlib_undefined);
370 man.hash.add(self.base.options.bind_global_refs_locally);
371
372 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
373 _ = try man.hit();
374 digest = man.final();
375
376 var prev_digest_buf: [digest.len]u8 = undefined;
377 const prev_digest: []u8 = directory.handle.readLink(id_symlink_basename, &prev_digest_buf) catch |err| blk: {
378 log.debug("MachO LLD new_digest={} readlink error: {}", .{ digest, @errorName(err) });
379 // Handle this as a cache miss.
380 break :blk prev_digest_buf[0..0];
381 };
382 if (mem.eql(u8, prev_digest, &digest)) {
383 log.debug("MachO LLD digest={} match - skipping invocation", .{digest});
384 // Hot diggity dog! The output binary is already there.
385 self.base.lock = man.toOwnedLock();
386 return;
387 }
388 log.debug("MachO LLD prev_digest={} new_digest={}", .{ prev_digest, digest });
389
390 // We are about to change the output file to be different, so we invalidate the build hash now.
391 directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
392 error.FileNotFound => {},
393 else => |e| return e,
394 };
395 }
396
397 // Create an LLD command line and invoke it.
398 var argv = std.ArrayList([]const u8).init(self.base.allocator);
399 defer argv.deinit();
400 // Even though we're calling LLD as a library it thinks the first argument is its own exe name.
401 try argv.append("lld");
402 if (is_obj) {
403 try argv.append("-r");
404 }
405
406 try argv.append("-error-limit");
407 try argv.append("0");
408
409 try argv.append("-demangle");
410
411 if (self.base.options.rdynamic) {
412 try argv.append("--export-dynamic");
413 }
414
415 try argv.appendSlice(self.base.options.extra_lld_args);
416
417 if (self.base.options.z_nodelete) {
418 try argv.append("-z");
419 try argv.append("nodelete");
420 }
421 if (self.base.options.z_defs) {
422 try argv.append("-z");
423 try argv.append("defs");
424 }
425
426 if (is_dyn_lib) {
427 try argv.append("-static");
428 } else {
429 try argv.append("-dynamic");
430 }
431
432 if (is_dyn_lib) {
433 try argv.append("-dylib");
434
435 if (self.base.options.version) |ver| {
436 const compat_vers = try std.fmt.allocPrint(arena, "{d}.0.0", .{ver.major});
437 try argv.append("-compatibility_version");
438 try argv.append(compat_vers);
439
440 const cur_vers = try std.fmt.allocPrint(arena, "{d}.{d}.{d}", .{ ver.major, ver.minor, ver.patch });
441 try argv.append("-current_version");
442 try argv.append(cur_vers);
443 }
444
445 // TODO getting an error when running an executable when doing this rpath thing
446 //Buf *dylib_install_name = buf_sprintf("@rpath/lib%s.%" ZIG_PRI_usize ".dylib",
447 // buf_ptr(g->root_out_name), g->version_major);
448 //try argv.append("-install_name");
449 //try argv.append(buf_ptr(dylib_install_name));
450 }
451
452 try argv.append("-arch");
453 try argv.append(darwinArchString(target.cpu.arch));
454
455 switch (target.os.tag) {
456 .macosx => {
457 try argv.append("-macosx_version_min");
458 },
459 .ios, .tvos, .watchos => switch (target.cpu.arch) {
460 .i386, .x86_64 => {
461 try argv.append("-ios_simulator_version_min");
462 },
463 else => {
464 try argv.append("-iphoneos_version_min");
465 },
466 },
467 else => unreachable,
468 }
469 const ver = target.os.version_range.semver.min;
470 const version_string = try std.fmt.allocPrint(arena, "{d}.{d}.{d}", .{ ver.major, ver.minor, ver.patch });
471 try argv.append(version_string);
472
473 try argv.append("-sdk_version");
474 try argv.append(version_string);
475
476 if (target_util.requiresPIE(target) and self.base.options.output_mode == .Exe) {
477 try argv.append("-pie");
478 }
479
480 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
481 try argv.append("-o");
482 try argv.append(full_out_path);
483
484 // rpaths
485 var rpath_table = std.StringHashMap(void).init(self.base.allocator);
486 defer rpath_table.deinit();
487 for (self.base.options.rpath_list) |rpath| {
488 if ((try rpath_table.fetchPut(rpath, {})) == null) {
489 try argv.append("-rpath");
490 try argv.append(rpath);
491 }
492 }
493 if (is_dyn_lib) {
494 if ((try rpath_table.fetchPut(full_out_path, {})) == null) {
495 try argv.append("-rpath");
496 try argv.append(full_out_path);
497 }
498 }
499
500 for (self.base.options.lib_dirs) |lib_dir| {
501 try argv.append("-L");
502 try argv.append(lib_dir);
503 }
504
505 // Positional arguments to the linker such as object files.
506 try argv.appendSlice(self.base.options.objects);
507
508 for (comp.c_object_table.items()) |entry| {
509 try argv.append(entry.key.status.success.object_path);
510 }
511 if (module_obj_path) |p| {
512 try argv.append(p);
513 }
514
515 // compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce
516 if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc) {
517 try argv.append(comp.compiler_rt_static_lib.?.full_object_path);
518 }
519
520 // Shared libraries.
521 const system_libs = self.base.options.system_libs.items();
522 try argv.ensureCapacity(argv.items.len + system_libs.len);
523 for (system_libs) |entry| {
524 const link_lib = entry.key;
525 // By this time, we depend on these libs being dynamically linked libraries and not static libraries
526 // (the check for that needs to be earlier), but they could be full paths to .dylib files, in which
527 // case we want to avoid prepending "-l".
528 const ext = Compilation.classifyFileExt(link_lib);
529 const arg = if (ext == .shared_library) link_lib else try std.fmt.allocPrint(arena, "-l{}", .{link_lib});
530 argv.appendAssumeCapacity(arg);
531 }
532
533 // libc++ dep
534 if (!is_obj and self.base.options.link_libcpp) {
535 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
536 try argv.append(comp.libcxx_static_lib.?.full_object_path);
537 }
538
539 // On Darwin, libSystem has libc in it, but also you have to use it
540 // to make syscalls because the syscall numbers are not documented
541 // and change between versions. So we always link against libSystem.
542 // LLD craps out if you do -lSystem cross compiling, so until that
543 // codebase gets some love from the new maintainers we're left with
544 // this dirty hack.
545 if (self.base.options.is_native_os) {
546 try argv.append("-lSystem");
547 }
548
549 for (self.base.options.framework_dirs) |framework_dir| {
550 try argv.append("-F");
551 try argv.append(framework_dir);
552 }
553 for (self.base.options.frameworks) |framework| {
554 try argv.append("-framework");
555 try argv.append(framework);
556 }
557
558 if (allow_shlib_undefined) {
559 try argv.append("-undefined");
560 try argv.append("dynamic_lookup");
561 }
562 if (self.base.options.bind_global_refs_locally) {
563 try argv.append("-Bsymbolic");
564 }
565
566 if (self.base.options.verbose_link) {
567 Compilation.dump_argv(argv.items);
568 }
569
570 // TODO allocSentinel crashed stage1 so this is working around it.
571 const new_argv_with_sentinel = try arena.alloc(?[*:0]const u8, argv.items.len + 1);
572 new_argv_with_sentinel[argv.items.len] = null;
573 const new_argv = new_argv_with_sentinel[0..argv.items.len :null];
574 for (argv.items) |arg, i| {
575 new_argv[i] = try arena.dupeZ(u8, arg);
576 }
577
578 var stderr_context: LLDContext = .{
579 .macho = self,
580 .data = std.ArrayList(u8).init(self.base.allocator),
581 };
582 defer stderr_context.data.deinit();
583 var stdout_context: LLDContext = .{
584 .macho = self,
585 .data = std.ArrayList(u8).init(self.base.allocator),
586 };
587 defer stdout_context.data.deinit();
588 const llvm = @import("../llvm.zig");
589 const ok = llvm.Link(
590 .MachO,
591 new_argv.ptr,
592 new_argv.len,
593 append_diagnostic,
594 @ptrToInt(&stdout_context),
595 @ptrToInt(&stderr_context),
596 );
597 if (stderr_context.oom or stdout_context.oom) return error.OutOfMemory;
598 if (stdout_context.data.items.len != 0) {
599 std.log.warn("unexpected LLD stdout: {}", .{stdout_context.data.items});
600 }
601 if (!ok) {
602 // TODO parse this output and surface with the Compilation API rather than
603 // directly outputting to stderr here.
604 std.debug.print("{}", .{stderr_context.data.items});
605 return error.LLDReportedFailure;
606 }
607 if (stderr_context.data.items.len != 0) {
608 std.log.warn("unexpected LLD stderr: {}", .{stderr_context.data.items});
609 }
610
611 if (!self.base.options.disable_lld_caching) {
612 // Update the dangling symlink with the digest. If it fails we can continue; it only
613 // means that the next invocation will have an unnecessary cache miss.
614 directory.handle.symLink(&digest, id_symlink_basename, .{}) catch |err| {
615 std.log.warn("failed to save linking hash digest symlink: {}", .{@errorName(err)});
616 };
617 // Again failure here only means an unnecessary cache miss.
618 man.writeManifest() catch |err| {
619 std.log.warn("failed to write cache manifest when linking: {}", .{@errorName(err)});
620 };
621 // We hang on to this lock so that the output file path can be used without
622 // other processes clobbering it.
623 self.base.lock = man.toOwnedLock();
624 }
625}
626
627const LLDContext = struct {
628 data: std.ArrayList(u8),
629 macho: *MachO,
630 oom: bool = false,
631};
632
633fn append_diagnostic(context: usize, ptr: [*]const u8, len: usize) callconv(.C) void {
634 const lld_context = @intToPtr(*LLDContext, context);
635 const msg = ptr[0..len];
636 lld_context.data.appendSlice(msg) catch |err| switch (err) {
637 error.OutOfMemory => lld_context.oom = true,
638 };
639}
640
641fn darwinArchString(arch: std.Target.Cpu.Arch) []const u8 {
642 return switch (arch) {
643 .aarch64, .aarch64_be, .aarch64_32 => "arm64",
644 .thumb, .arm => "arm",
645 .thumbeb, .armeb => "armeb",
646 .powerpc => "ppc",
647 .powerpc64 => "ppc64",
648 .powerpc64le => "ppc64le",
649 else => @tagName(arch),
650 };
651}
652
285pub fn deinit(self: *MachO) void {653pub fn deinit(self: *MachO) void {
286 self.offset_table.deinit(self.base.allocator);654 self.offset_table.deinit(self.base.allocator);
287 self.string_table.deinit(self.base.allocator);655 self.string_table.deinit(self.base.allocator);