| ... | @@ -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; |
| 321 | | 321 | |
| 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 | } |
| 393 | | 392 | |
| 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 | } | | |
| 402 | | 394 | |
| 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]; |
| 405 | | 402 | |
| 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; |
| 407 | | 405 | |
| 408 | if (self.base.options.rdynamic) { | 406 | if (module_obj_path) |p| |
| 409 | try argv.append("--export-dynamic"); | 407 | break :blk p; |
| 410 | } | | |
| 411 | | 408 | |
| 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"); |
| 413 | | 424 | |
| 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 | } | | |
| 422 | | 427 | |
| 423 | if (is_dyn_lib) { | 428 | try argv.append("-demangle"); |
| 424 | try argv.append("-static"); | | |
| 425 | } else { | | |
| 426 | try argv.append("-dynamic"); | | |
| 427 | } | | |
| 428 | | 429 | |
| 429 | if (is_dyn_lib) { | 430 | if (self.base.options.rdynamic) { |
| 430 | try argv.append("-dylib"); | 431 | try argv.append("--export-dynamic"); |
| | 432 | } |
| 431 | | 433 | |
| 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); | | |
| 436 | | 435 | |
| 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 | } |
| 441 | | 444 | |
| 442 | // TODO getting an error when running an executable when doing this rpath thing | 445 | 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 | } | | |
| 448 | | 450 | |
| 449 | try argv.append("-arch"); | 451 | if (is_dyn_lib) { |
| 450 | try argv.append(darwinArchString(target.cpu.arch)); | 452 | try argv.append("-dylib"); |
| 451 | | 453 | |
| 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); | | |
| 469 | | 491 | |
| 470 | try argv.append("-sdk_version"); | 492 | try argv.append("-sdk_version"); |
| 471 | try argv.append(version_string); | 493 | try argv.append(version_string); |
| 472 | | 494 | |
| 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 | } |
| 476 | | 498 | |
| 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 | |
| 480 | | 502 | // rpaths |
| 481 | // rpaths | 503 | 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 | } | | |
| 496 | | 517 | |
| 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 | } |
| 501 | | 522 | |
| 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); |
| 504 | | 525 | |
| 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 | } |
| 511 | | 532 | |
| 512 | // compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce | 533 | // 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 | } |
| 516 | | 537 | |
| 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 libraries | 543 | // 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 which | 544 | // (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 | } |
| 529 | | 550 | |
| 530 | // libc++ dep | 551 | // 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 | } |
| 535 | | 556 | |
| 536 | // On Darwin, libSystem has libc in it, but also you have to use it | 557 | // On Darwin, libSystem has libc in it, but also you have to use it |
| 537 | // to make syscalls because the syscall numbers are not documented | 558 | // 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 that | 560 | // LLD craps out if you do -lSystem cross compiling, so until that |
| 540 | // codebase gets some love from the new maintainers we're left with | 561 | // 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 | } |
| 545 | | 566 | |
| 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 | } |
| 554 | | 575 | |
| 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 | } |
| 562 | | 583 | |
| 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 | } |
| 566 | | 587 | |
| 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 | } |
| 571 | | 592 | |
| 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 than | 617 | // 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 | } |
| 604 | | 626 | |
| 605 | if (!self.base.options.disable_lld_caching) { | 627 | if (!self.base.options.disable_lld_caching) { |