authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-30 01:00:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-30 01:04:30-07:00
log3249e5d952cfcecca999391ffc02cce92ff8fcc4
tree62f8f37e804d2fb2a817e090ce882100b06cc728
parent2a893efae12b2f80d0ff5fd883fdaeb00d9425e4

MachO: add the same workaround for no -r LLD flag support

This is the MachO equivalent for the code added to COFF for doing the file copy when the input and output are both just one object file.

2 files changed, 202 insertions(+), 180 deletions(-)

src/link/MachO.zig+200-178
...@@ -319,7 +319,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -319,7 +319,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
319 break :blk full_obj_path;319 break :blk full_obj_path;
320 } else null;320 } else null;
321321
322 const is_obj = self.base.options.output_mode == .Obj;
323 const is_lib = self.base.options.output_mode == .Lib;322 const is_lib = self.base.options.output_mode == .Lib;
324 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;323 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;324 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
...@@ -391,215 +390,238 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -391,215 +390,238 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
391 };390 };
392 }391 }
393392
394 // Create an LLD command line and invoke it.393 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
395 var argv = std.ArrayList([]const u8).init(self.base.allocator);
396 defer argv.deinit();
397 // Even though we're calling LLD as a library it thinks the first argument is its own exe name.
398 try argv.append("lld");
399 if (is_obj) {
400 try argv.append("-r");
401 }
402394
403 try argv.append("-error-limit");395 if (self.base.options.output_mode == .Obj) {
404 try argv.append("0");396 // LLD's MachO driver does not support the equvialent of `-r` so we do a simple file copy
397 // here. TODO: think carefully about how we can avoid this redundant operation when doing
398 // build-obj. See also the corresponding TODO in linkAsArchive.
399 const the_object_path = blk: {
400 if (self.base.options.objects.len != 0)
401 break :blk self.base.options.objects[0];
405402
406 try argv.append("-demangle");403 if (comp.c_object_table.count() != 0)
404 break :blk comp.c_object_table.items()[0].key.status.success.object_path;
407405
408 if (self.base.options.rdynamic) {406 if (module_obj_path) |p|
409 try argv.append("--export-dynamic");407 break :blk p;
410 }
411408
412 try argv.appendSlice(self.base.options.extra_lld_args);409 // TODO I think this is unreachable. Audit this situation when solving the above TODO
410 // regarding eliding redundant object -> object transformations.
411 return error.NoObjectsToLink;
412 };
413 // This can happen when using --enable-cache and using the stage1 backend. In this case
414 // we can skip the file copy.
415 if (!mem.eql(u8, the_object_path, full_out_path)) {
416 try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
417 }
418 } else {
419 // Create an LLD command line and invoke it.
420 var argv = std.ArrayList([]const u8).init(self.base.allocator);
421 defer argv.deinit();
422 // Even though we're calling LLD as a library it thinks the first argument is its own exe name.
423 try argv.append("lld");
413424
414 if (self.base.options.z_nodelete) {425 try argv.append("-error-limit");
415 try argv.append("-z");426 try argv.append("0");
416 try argv.append("nodelete");
417 }
418 if (self.base.options.z_defs) {
419 try argv.append("-z");
420 try argv.append("defs");
421 }
422427
423 if (is_dyn_lib) {428 try argv.append("-demangle");
424 try argv.append("-static");
425 } else {
426 try argv.append("-dynamic");
427 }
428429
429 if (is_dyn_lib) {430 if (self.base.options.rdynamic) {
430 try argv.append("-dylib");431 try argv.append("--export-dynamic");
432 }
431433
432 if (self.base.options.version) |ver| {434 try argv.appendSlice(self.base.options.extra_lld_args);
433 const compat_vers = try std.fmt.allocPrint(arena, "{d}.0.0", .{ver.major});
434 try argv.append("-compatibility_version");
435 try argv.append(compat_vers);
436435
437 const cur_vers = try std.fmt.allocPrint(arena, "{d}.{d}.{d}", .{ ver.major, ver.minor, ver.patch });436 if (self.base.options.z_nodelete) {
438 try argv.append("-current_version");437 try argv.append("-z");
439 try argv.append(cur_vers);438 try argv.append("nodelete");
439 }
440 if (self.base.options.z_defs) {
441 try argv.append("-z");
442 try argv.append("defs");
440 }443 }
441444
442 // TODO getting an error when running an executable when doing this rpath thing445 if (is_dyn_lib) {
443 //Buf *dylib_install_name = buf_sprintf("@rpath/lib%s.%" ZIG_PRI_usize ".dylib",446 try argv.append("-static");
444 // buf_ptr(g->root_out_name), g->version_major);447 } else {
445 //try argv.append("-install_name");448 try argv.append("-dynamic");
446 //try argv.append(buf_ptr(dylib_install_name));449 }
447 }
448450
449 try argv.append("-arch");451 if (is_dyn_lib) {
450 try argv.append(darwinArchString(target.cpu.arch));452 try argv.append("-dylib");
451453
452 switch (target.os.tag) {454 if (self.base.options.version) |ver| {
453 .macosx => {455 const compat_vers = try std.fmt.allocPrint(arena, "{d}.0.0", .{ver.major});
454 try argv.append("-macosx_version_min");456 try argv.append("-compatibility_version");
455 },457 try argv.append(compat_vers);
456 .ios, .tvos, .watchos => switch (target.cpu.arch) {458
457 .i386, .x86_64 => {459 const cur_vers = try std.fmt.allocPrint(arena, "{d}.{d}.{d}", .{ ver.major, ver.minor, ver.patch });
458 try argv.append("-ios_simulator_version_min");460 try argv.append("-current_version");
461 try argv.append(cur_vers);
462 }
463
464 // TODO getting an error when running an executable when doing this rpath thing
465 //Buf *dylib_install_name = buf_sprintf("@rpath/lib%s.%" ZIG_PRI_usize ".dylib",
466 // buf_ptr(g->root_out_name), g->version_major);
467 //try argv.append("-install_name");
468 //try argv.append(buf_ptr(dylib_install_name));
469 }
470
471 try argv.append("-arch");
472 try argv.append(darwinArchString(target.cpu.arch));
473
474 switch (target.os.tag) {
475 .macosx => {
476 try argv.append("-macosx_version_min");
459 },477 },
460 else => {478 .ios, .tvos, .watchos => switch (target.cpu.arch) {
461 try argv.append("-iphoneos_version_min");479 .i386, .x86_64 => {
480 try argv.append("-ios_simulator_version_min");
481 },
482 else => {
483 try argv.append("-iphoneos_version_min");
484 },
462 },485 },
463 },486 else => unreachable,
464 else => unreachable,487 }
465 }488 const ver = target.os.version_range.semver.min;
466 const ver = target.os.version_range.semver.min;489 const version_string = try std.fmt.allocPrint(arena, "{d}.{d}.{d}", .{ ver.major, ver.minor, ver.patch });
467 const version_string = try std.fmt.allocPrint(arena, "{d}.{d}.{d}", .{ ver.major, ver.minor, ver.patch });490 try argv.append(version_string);
468 try argv.append(version_string);
469491
470 try argv.append("-sdk_version");492 try argv.append("-sdk_version");
471 try argv.append(version_string);493 try argv.append(version_string);
472494
473 if (target_util.requiresPIE(target) and self.base.options.output_mode == .Exe) {495 if (target_util.requiresPIE(target) and self.base.options.output_mode == .Exe) {
474 try argv.append("-pie");496 try argv.append("-pie");
475 }497 }
476498
477 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});499 try argv.append("-o");
478 try argv.append("-o");500 try argv.append(full_out_path);
479 try argv.append(full_out_path);501
480502 // rpaths
481 // rpaths503 var rpath_table = std.StringHashMap(void).init(self.base.allocator);
482 var rpath_table = std.StringHashMap(void).init(self.base.allocator);504 defer rpath_table.deinit();
483 defer rpath_table.deinit();505 for (self.base.options.rpath_list) |rpath| {
484 for (self.base.options.rpath_list) |rpath| {506 if ((try rpath_table.fetchPut(rpath, {})) == null) {
485 if ((try rpath_table.fetchPut(rpath, {})) == null) {507 try argv.append("-rpath");
486 try argv.append("-rpath");508 try argv.append(rpath);
487 try argv.append(rpath);509 }
488 }510 }
489 }511 if (is_dyn_lib) {
490 if (is_dyn_lib) {512 if ((try rpath_table.fetchPut(full_out_path, {})) == null) {
491 if ((try rpath_table.fetchPut(full_out_path, {})) == null) {513 try argv.append("-rpath");
492 try argv.append("-rpath");514 try argv.append(full_out_path);
493 try argv.append(full_out_path);515 }
494 }516 }
495 }
496517
497 for (self.base.options.lib_dirs) |lib_dir| {518 for (self.base.options.lib_dirs) |lib_dir| {
498 try argv.append("-L");519 try argv.append("-L");
499 try argv.append(lib_dir);520 try argv.append(lib_dir);
500 }521 }
501522
502 // Positional arguments to the linker such as object files.523 // Positional arguments to the linker such as object files.
503 try argv.appendSlice(self.base.options.objects);524 try argv.appendSlice(self.base.options.objects);
504525
505 for (comp.c_object_table.items()) |entry| {526 for (comp.c_object_table.items()) |entry| {
506 try argv.append(entry.key.status.success.object_path);527 try argv.append(entry.key.status.success.object_path);
507 }528 }
508 if (module_obj_path) |p| {529 if (module_obj_path) |p| {
509 try argv.append(p);530 try argv.append(p);
510 }531 }
511532
512 // compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce533 // compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce
513 if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc) {534 if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc) {
514 try argv.append(comp.compiler_rt_static_lib.?.full_object_path);535 try argv.append(comp.compiler_rt_static_lib.?.full_object_path);
515 }536 }
516537
517 // Shared libraries.538 // Shared libraries.
518 const system_libs = self.base.options.system_libs.items();539 const system_libs = self.base.options.system_libs.items();
519 try argv.ensureCapacity(argv.items.len + system_libs.len);540 try argv.ensureCapacity(argv.items.len + system_libs.len);
520 for (system_libs) |entry| {541 for (system_libs) |entry| {
521 const link_lib = entry.key;542 const link_lib = entry.key;
522 // By this time, we depend on these libs being dynamically linked libraries and not static libraries543 // By this time, we depend on these libs being dynamically linked libraries and not static libraries
523 // (the check for that needs to be earlier), but they could be full paths to .dylib files, in which544 // (the check for that needs to be earlier), but they could be full paths to .dylib files, in which
524 // case we want to avoid prepending "-l".545 // case we want to avoid prepending "-l".
525 const ext = Compilation.classifyFileExt(link_lib);546 const ext = Compilation.classifyFileExt(link_lib);
526 const arg = if (ext == .shared_library) link_lib else try std.fmt.allocPrint(arena, "-l{}", .{link_lib});547 const arg = if (ext == .shared_library) link_lib else try std.fmt.allocPrint(arena, "-l{}", .{link_lib});
527 argv.appendAssumeCapacity(arg);548 argv.appendAssumeCapacity(arg);
528 }549 }
529550
530 // libc++ dep551 // libc++ dep
531 if (!is_obj and self.base.options.link_libcpp) {552 if (self.base.options.link_libcpp) {
532 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);553 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
533 try argv.append(comp.libcxx_static_lib.?.full_object_path);554 try argv.append(comp.libcxx_static_lib.?.full_object_path);
534 }555 }
535556
536 // On Darwin, libSystem has libc in it, but also you have to use it557 // On Darwin, libSystem has libc in it, but also you have to use it
537 // to make syscalls because the syscall numbers are not documented558 // to make syscalls because the syscall numbers are not documented
538 // and change between versions. So we always link against libSystem.559 // and change between versions. So we always link against libSystem.
539 // LLD craps out if you do -lSystem cross compiling, so until that560 // LLD craps out if you do -lSystem cross compiling, so until that
540 // codebase gets some love from the new maintainers we're left with561 // codebase gets some love from the new maintainers we're left with
541 // this dirty hack.562 // this dirty hack.
542 if (self.base.options.is_native_os) {563 if (self.base.options.is_native_os) {
543 try argv.append("-lSystem");564 try argv.append("-lSystem");
544 }565 }
545566
546 for (self.base.options.framework_dirs) |framework_dir| {567 for (self.base.options.framework_dirs) |framework_dir| {
547 try argv.append("-F");568 try argv.append("-F");
548 try argv.append(framework_dir);569 try argv.append(framework_dir);
549 }570 }
550 for (self.base.options.frameworks) |framework| {571 for (self.base.options.frameworks) |framework| {
551 try argv.append("-framework");572 try argv.append("-framework");
552 try argv.append(framework);573 try argv.append(framework);
553 }574 }
554575
555 if (allow_shlib_undefined) {576 if (allow_shlib_undefined) {
556 try argv.append("-undefined");577 try argv.append("-undefined");
557 try argv.append("dynamic_lookup");578 try argv.append("dynamic_lookup");
558 }579 }
559 if (self.base.options.bind_global_refs_locally) {580 if (self.base.options.bind_global_refs_locally) {
560 try argv.append("-Bsymbolic");581 try argv.append("-Bsymbolic");
561 }582 }
562583
563 if (self.base.options.verbose_link) {584 if (self.base.options.verbose_link) {
564 Compilation.dump_argv(argv.items);585 Compilation.dump_argv(argv.items);
565 }586 }
566587
567 const new_argv = try arena.allocSentinel(?[*:0]const u8, argv.items.len, null);588 const new_argv = try arena.allocSentinel(?[*:0]const u8, argv.items.len, null);
568 for (argv.items) |arg, i| {589 for (argv.items) |arg, i| {
569 new_argv[i] = try arena.dupeZ(u8, arg);590 new_argv[i] = try arena.dupeZ(u8, arg);
570 }591 }
571592
572 var stderr_context: LLDContext = .{593 var stderr_context: LLDContext = .{
573 .macho = self,594 .macho = self,
574 .data = std.ArrayList(u8).init(self.base.allocator),595 .data = std.ArrayList(u8).init(self.base.allocator),
575 };596 };
576 defer stderr_context.data.deinit();597 defer stderr_context.data.deinit();
577 var stdout_context: LLDContext = .{598 var stdout_context: LLDContext = .{
578 .macho = self,599 .macho = self,
579 .data = std.ArrayList(u8).init(self.base.allocator),600 .data = std.ArrayList(u8).init(self.base.allocator),
580 };601 };
581 defer stdout_context.data.deinit();602 defer stdout_context.data.deinit();
582 const llvm = @import("../llvm.zig");603 const llvm = @import("../llvm.zig");
583 const ok = llvm.Link(604 const ok = llvm.Link(
584 .MachO,605 .MachO,
585 new_argv.ptr,606 new_argv.ptr,
586 new_argv.len,607 new_argv.len,
587 append_diagnostic,608 append_diagnostic,
588 @ptrToInt(&stdout_context),609 @ptrToInt(&stdout_context),
589 @ptrToInt(&stderr_context),610 @ptrToInt(&stderr_context),
590 );611 );
591 if (stderr_context.oom or stdout_context.oom) return error.OutOfMemory;612 if (stderr_context.oom or stdout_context.oom) return error.OutOfMemory;
592 if (stdout_context.data.items.len != 0) {613 if (stdout_context.data.items.len != 0) {
593 std.log.warn("unexpected LLD stdout: {}", .{stdout_context.data.items});614 std.log.warn("unexpected LLD stdout: {}", .{stdout_context.data.items});
594 }615 }
595 if (!ok) {616 if (!ok) {
596 // TODO parse this output and surface with the Compilation API rather than617 // TODO parse this output and surface with the Compilation API rather than
597 // directly outputting to stderr here.618 // directly outputting to stderr here.
598 std.debug.print("{}", .{stderr_context.data.items});619 std.debug.print("{}", .{stderr_context.data.items});
599 return error.LLDReportedFailure;620 return error.LLDReportedFailure;
600 }621 }
601 if (stderr_context.data.items.len != 0) {622 if (stderr_context.data.items.len != 0) {
602 std.log.warn("unexpected LLD stderr: {}", .{stderr_context.data.items});623 std.log.warn("unexpected LLD stderr: {}", .{stderr_context.data.items});
624 }
603 }625 }
604626
605 if (!self.base.options.disable_lld_caching) {627 if (!self.base.options.disable_lld_caching) {
src/main.zig+2-2
...@@ -1337,12 +1337,12 @@ fn buildOutputType(...@@ -1337,12 +1337,12 @@ fn buildOutputType(
1337 }1337 }
1338 };1338 };
13391339
1340 if (output_mode == .Obj and object_format == .coff) {1340 if (output_mode == .Obj and (object_format == .coff or object_format == .macho)) {
1341 const total_obj_count = c_source_files.items.len +1341 const total_obj_count = c_source_files.items.len +
1342 @boolToInt(root_src_file != null) +1342 @boolToInt(root_src_file != null) +
1343 link_objects.items.len;1343 link_objects.items.len;
1344 if (total_obj_count > 1) {1344 if (total_obj_count > 1) {
1345 fatal("COFF does not support linking multiple objects into one", .{});1345 fatal("{s} does not support linking multiple objects into one", .{@tagName(object_format)});
1346 }1346 }
1347 }1347 }
13481348