| ... | ... | @@ -319,7 +319,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 319 | 319 | break :blk full_obj_path; |
| 320 | 320 | } else null; |
| 321 | 321 | |
| 322 | | const is_obj = self.base.options.output_mode == .Obj; |
| 323 | 322 | const is_lib = self.base.options.output_mode == .Lib; |
| 324 | 323 | const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib; |
| 325 | 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 | 390 | }; |
| 392 | 391 | } |
| 393 | 392 | |
| 394 | | // Create an LLD command line and invoke it. |
| 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 | | } |
| 393 | const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); |
| 402 | 394 | |
| 403 | | try argv.append("-error-limit"); |
| 404 | | try argv.append("0"); |
| 395 | if (self.base.options.output_mode == .Obj) { |
| 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) { |
| 409 | | try argv.append("--export-dynamic"); |
| 410 | | } |
| 406 | if (module_obj_path) |p| |
| 407 | break :blk p; |
| 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) { |
| 415 | | try argv.append("-z"); |
| 416 | | try argv.append("nodelete"); |
| 417 | | } |
| 418 | | if (self.base.options.z_defs) { |
| 419 | | try argv.append("-z"); |
| 420 | | try argv.append("defs"); |
| 421 | | } |
| 425 | try argv.append("-error-limit"); |
| 426 | try argv.append("0"); |
| 422 | 427 | |
| 423 | | if (is_dyn_lib) { |
| 424 | | try argv.append("-static"); |
| 425 | | } else { |
| 426 | | try argv.append("-dynamic"); |
| 427 | | } |
| 428 | try argv.append("-demangle"); |
| 428 | 429 | |
| 429 | | if (is_dyn_lib) { |
| 430 | | try argv.append("-dylib"); |
| 430 | if (self.base.options.rdynamic) { |
| 431 | try argv.append("--export-dynamic"); |
| 432 | } |
| 431 | 433 | |
| 432 | | if (self.base.options.version) |ver| { |
| 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); |
| 434 | try argv.appendSlice(self.base.options.extra_lld_args); |
| 436 | 435 | |
| 437 | | const cur_vers = try std.fmt.allocPrint(arena, "{d}.{d}.{d}", .{ ver.major, ver.minor, ver.patch }); |
| 438 | | try argv.append("-current_version"); |
| 439 | | try argv.append(cur_vers); |
| 436 | if (self.base.options.z_nodelete) { |
| 437 | try argv.append("-z"); |
| 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 |
| 443 | | //Buf *dylib_install_name = buf_sprintf("@rpath/lib%s.%" ZIG_PRI_usize ".dylib", |
| 444 | | // buf_ptr(g->root_out_name), g->version_major); |
| 445 | | //try argv.append("-install_name"); |
| 446 | | //try argv.append(buf_ptr(dylib_install_name)); |
| 447 | | } |
| 445 | if (is_dyn_lib) { |
| 446 | try argv.append("-static"); |
| 447 | } else { |
| 448 | try argv.append("-dynamic"); |
| 449 | } |
| 448 | 450 | |
| 449 | | try argv.append("-arch"); |
| 450 | | try argv.append(darwinArchString(target.cpu.arch)); |
| 451 | if (is_dyn_lib) { |
| 452 | try argv.append("-dylib"); |
| 451 | 453 | |
| 452 | | switch (target.os.tag) { |
| 453 | | .macosx => { |
| 454 | | try argv.append("-macosx_version_min"); |
| 455 | | }, |
| 456 | | .ios, .tvos, .watchos => switch (target.cpu.arch) { |
| 457 | | .i386, .x86_64 => { |
| 458 | | try argv.append("-ios_simulator_version_min"); |
| 454 | if (self.base.options.version) |ver| { |
| 455 | const compat_vers = try std.fmt.allocPrint(arena, "{d}.0.0", .{ver.major}); |
| 456 | try argv.append("-compatibility_version"); |
| 457 | try argv.append(compat_vers); |
| 458 | |
| 459 | const cur_vers = try std.fmt.allocPrint(arena, "{d}.{d}.{d}", .{ ver.major, ver.minor, ver.patch }); |
| 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 => { |
| 461 | | try argv.append("-iphoneos_version_min"); |
| 478 | .ios, .tvos, .watchos => switch (target.cpu.arch) { |
| 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 | | }, |
| 464 | | else => unreachable, |
| 465 | | } |
| 466 | | const ver = target.os.version_range.semver.min; |
| 467 | | const version_string = try std.fmt.allocPrint(arena, "{d}.{d}.{d}", .{ ver.major, ver.minor, ver.patch }); |
| 468 | | try argv.append(version_string); |
| 486 | else => unreachable, |
| 487 | } |
| 488 | 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 }); |
| 490 | try argv.append(version_string); |
| 469 | 491 | |
| 470 | | try argv.append("-sdk_version"); |
| 471 | | try argv.append(version_string); |
| 492 | try argv.append("-sdk_version"); |
| 493 | try argv.append(version_string); |
| 472 | 494 | |
| 473 | | if (target_util.requiresPIE(target) and self.base.options.output_mode == .Exe) { |
| 474 | | try argv.append("-pie"); |
| 475 | | } |
| 495 | if (target_util.requiresPIE(target) and self.base.options.output_mode == .Exe) { |
| 496 | try argv.append("-pie"); |
| 497 | } |
| 476 | 498 | |
| 477 | | const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); |
| 478 | | try argv.append("-o"); |
| 479 | | try argv.append(full_out_path); |
| 480 | | |
| 481 | | // rpaths |
| 482 | | var rpath_table = std.StringHashMap(void).init(self.base.allocator); |
| 483 | | defer rpath_table.deinit(); |
| 484 | | for (self.base.options.rpath_list) |rpath| { |
| 485 | | if ((try rpath_table.fetchPut(rpath, {})) == null) { |
| 486 | | try argv.append("-rpath"); |
| 487 | | try argv.append(rpath); |
| 499 | try argv.append("-o"); |
| 500 | try argv.append(full_out_path); |
| 501 | |
| 502 | // rpaths |
| 503 | var rpath_table = std.StringHashMap(void).init(self.base.allocator); |
| 504 | defer rpath_table.deinit(); |
| 505 | for (self.base.options.rpath_list) |rpath| { |
| 506 | if ((try rpath_table.fetchPut(rpath, {})) == null) { |
| 507 | try argv.append("-rpath"); |
| 508 | try argv.append(rpath); |
| 509 | } |
| 488 | 510 | } |
| 489 | | } |
| 490 | | if (is_dyn_lib) { |
| 491 | | if ((try rpath_table.fetchPut(full_out_path, {})) == null) { |
| 492 | | try argv.append("-rpath"); |
| 493 | | try argv.append(full_out_path); |
| 511 | if (is_dyn_lib) { |
| 512 | if ((try rpath_table.fetchPut(full_out_path, {})) == null) { |
| 513 | try argv.append("-rpath"); |
| 514 | try argv.append(full_out_path); |
| 515 | } |
| 494 | 516 | } |
| 495 | | } |
| 496 | 517 | |
| 497 | | for (self.base.options.lib_dirs) |lib_dir| { |
| 498 | | try argv.append("-L"); |
| 499 | | try argv.append(lib_dir); |
| 500 | | } |
| 518 | for (self.base.options.lib_dirs) |lib_dir| { |
| 519 | try argv.append("-L"); |
| 520 | try argv.append(lib_dir); |
| 521 | } |
| 501 | 522 | |
| 502 | | // Positional arguments to the linker such as object files. |
| 503 | | try argv.appendSlice(self.base.options.objects); |
| 523 | // Positional arguments to the linker such as object files. |
| 524 | try argv.appendSlice(self.base.options.objects); |
| 504 | 525 | |
| 505 | | for (comp.c_object_table.items()) |entry| { |
| 506 | | try argv.append(entry.key.status.success.object_path); |
| 507 | | } |
| 508 | | if (module_obj_path) |p| { |
| 509 | | try argv.append(p); |
| 510 | | } |
| 526 | for (comp.c_object_table.items()) |entry| { |
| 527 | try argv.append(entry.key.status.success.object_path); |
| 528 | } |
| 529 | if (module_obj_path) |p| { |
| 530 | try argv.append(p); |
| 531 | } |
| 511 | 532 | |
| 512 | | // 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) { |
| 514 | | try argv.append(comp.compiler_rt_static_lib.?.full_object_path); |
| 515 | | } |
| 533 | // compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce |
| 534 | if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc) { |
| 535 | try argv.append(comp.compiler_rt_static_lib.?.full_object_path); |
| 536 | } |
| 516 | 537 | |
| 517 | | // Shared libraries. |
| 518 | | const system_libs = self.base.options.system_libs.items(); |
| 519 | | try argv.ensureCapacity(argv.items.len + system_libs.len); |
| 520 | | for (system_libs) |entry| { |
| 521 | | const link_lib = entry.key; |
| 522 | | // 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 |
| 524 | | // case we want to avoid prepending "-l". |
| 525 | | const ext = Compilation.classifyFileExt(link_lib); |
| 526 | | const arg = if (ext == .shared_library) link_lib else try std.fmt.allocPrint(arena, "-l{}", .{link_lib}); |
| 527 | | argv.appendAssumeCapacity(arg); |
| 528 | | } |
| 538 | // Shared libraries. |
| 539 | const system_libs = self.base.options.system_libs.items(); |
| 540 | try argv.ensureCapacity(argv.items.len + system_libs.len); |
| 541 | for (system_libs) |entry| { |
| 542 | const link_lib = entry.key; |
| 543 | // By this time, we depend on these libs being dynamically linked libraries and not static libraries |
| 544 | // (the check for that needs to be earlier), but they could be full paths to .dylib files, in which |
| 545 | // case we want to avoid prepending "-l". |
| 546 | const ext = Compilation.classifyFileExt(link_lib); |
| 547 | const arg = if (ext == .shared_library) link_lib else try std.fmt.allocPrint(arena, "-l{}", .{link_lib}); |
| 548 | argv.appendAssumeCapacity(arg); |
| 549 | } |
| 529 | 550 | |
| 530 | | // libc++ dep |
| 531 | | if (!is_obj and self.base.options.link_libcpp) { |
| 532 | | try argv.append(comp.libcxxabi_static_lib.?.full_object_path); |
| 533 | | try argv.append(comp.libcxx_static_lib.?.full_object_path); |
| 534 | | } |
| 551 | // libc++ dep |
| 552 | if (self.base.options.link_libcpp) { |
| 553 | try argv.append(comp.libcxxabi_static_lib.?.full_object_path); |
| 554 | try argv.append(comp.libcxx_static_lib.?.full_object_path); |
| 555 | } |
| 535 | 556 | |
| 536 | | // 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 |
| 538 | | // and change between versions. So we always link against libSystem. |
| 539 | | // 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 |
| 541 | | // this dirty hack. |
| 542 | | if (self.base.options.is_native_os) { |
| 543 | | try argv.append("-lSystem"); |
| 544 | | } |
| 557 | // On Darwin, libSystem has libc in it, but also you have to use it |
| 558 | // to make syscalls because the syscall numbers are not documented |
| 559 | // and change between versions. So we always link against libSystem. |
| 560 | // LLD craps out if you do -lSystem cross compiling, so until that |
| 561 | // codebase gets some love from the new maintainers we're left with |
| 562 | // this dirty hack. |
| 563 | if (self.base.options.is_native_os) { |
| 564 | try argv.append("-lSystem"); |
| 565 | } |
| 545 | 566 | |
| 546 | | for (self.base.options.framework_dirs) |framework_dir| { |
| 547 | | try argv.append("-F"); |
| 548 | | try argv.append(framework_dir); |
| 549 | | } |
| 550 | | for (self.base.options.frameworks) |framework| { |
| 551 | | try argv.append("-framework"); |
| 552 | | try argv.append(framework); |
| 553 | | } |
| 567 | for (self.base.options.framework_dirs) |framework_dir| { |
| 568 | try argv.append("-F"); |
| 569 | try argv.append(framework_dir); |
| 570 | } |
| 571 | for (self.base.options.frameworks) |framework| { |
| 572 | try argv.append("-framework"); |
| 573 | try argv.append(framework); |
| 574 | } |
| 554 | 575 | |
| 555 | | if (allow_shlib_undefined) { |
| 556 | | try argv.append("-undefined"); |
| 557 | | try argv.append("dynamic_lookup"); |
| 558 | | } |
| 559 | | if (self.base.options.bind_global_refs_locally) { |
| 560 | | try argv.append("-Bsymbolic"); |
| 561 | | } |
| 576 | if (allow_shlib_undefined) { |
| 577 | try argv.append("-undefined"); |
| 578 | try argv.append("dynamic_lookup"); |
| 579 | } |
| 580 | if (self.base.options.bind_global_refs_locally) { |
| 581 | try argv.append("-Bsymbolic"); |
| 582 | } |
| 562 | 583 | |
| 563 | | if (self.base.options.verbose_link) { |
| 564 | | Compilation.dump_argv(argv.items); |
| 565 | | } |
| 584 | if (self.base.options.verbose_link) { |
| 585 | Compilation.dump_argv(argv.items); |
| 586 | } |
| 566 | 587 | |
| 567 | | const new_argv = try arena.allocSentinel(?[*:0]const u8, argv.items.len, null); |
| 568 | | for (argv.items) |arg, i| { |
| 569 | | new_argv[i] = try arena.dupeZ(u8, arg); |
| 570 | | } |
| 588 | const new_argv = try arena.allocSentinel(?[*:0]const u8, argv.items.len, null); |
| 589 | for (argv.items) |arg, i| { |
| 590 | new_argv[i] = try arena.dupeZ(u8, arg); |
| 591 | } |
| 571 | 592 | |
| 572 | | var stderr_context: LLDContext = .{ |
| 573 | | .macho = self, |
| 574 | | .data = std.ArrayList(u8).init(self.base.allocator), |
| 575 | | }; |
| 576 | | defer stderr_context.data.deinit(); |
| 577 | | var stdout_context: LLDContext = .{ |
| 578 | | .macho = self, |
| 579 | | .data = std.ArrayList(u8).init(self.base.allocator), |
| 580 | | }; |
| 581 | | defer stdout_context.data.deinit(); |
| 582 | | const llvm = @import("../llvm.zig"); |
| 583 | | const ok = llvm.Link( |
| 584 | | .MachO, |
| 585 | | new_argv.ptr, |
| 586 | | new_argv.len, |
| 587 | | append_diagnostic, |
| 588 | | @ptrToInt(&stdout_context), |
| 589 | | @ptrToInt(&stderr_context), |
| 590 | | ); |
| 591 | | if (stderr_context.oom or stdout_context.oom) return error.OutOfMemory; |
| 592 | | if (stdout_context.data.items.len != 0) { |
| 593 | | std.log.warn("unexpected LLD stdout: {}", .{stdout_context.data.items}); |
| 594 | | } |
| 595 | | if (!ok) { |
| 596 | | // TODO parse this output and surface with the Compilation API rather than |
| 597 | | // directly outputting to stderr here. |
| 598 | | std.debug.print("{}", .{stderr_context.data.items}); |
| 599 | | return error.LLDReportedFailure; |
| 600 | | } |
| 601 | | if (stderr_context.data.items.len != 0) { |
| 602 | | std.log.warn("unexpected LLD stderr: {}", .{stderr_context.data.items}); |
| 593 | var stderr_context: LLDContext = .{ |
| 594 | .macho = self, |
| 595 | .data = std.ArrayList(u8).init(self.base.allocator), |
| 596 | }; |
| 597 | defer stderr_context.data.deinit(); |
| 598 | var stdout_context: LLDContext = .{ |
| 599 | .macho = self, |
| 600 | .data = std.ArrayList(u8).init(self.base.allocator), |
| 601 | }; |
| 602 | defer stdout_context.data.deinit(); |
| 603 | const llvm = @import("../llvm.zig"); |
| 604 | const ok = llvm.Link( |
| 605 | .MachO, |
| 606 | new_argv.ptr, |
| 607 | new_argv.len, |
| 608 | append_diagnostic, |
| 609 | @ptrToInt(&stdout_context), |
| 610 | @ptrToInt(&stderr_context), |
| 611 | ); |
| 612 | if (stderr_context.oom or stdout_context.oom) return error.OutOfMemory; |
| 613 | if (stdout_context.data.items.len != 0) { |
| 614 | std.log.warn("unexpected LLD stdout: {}", .{stdout_context.data.items}); |
| 615 | } |
| 616 | if (!ok) { |
| 617 | // TODO parse this output and surface with the Compilation API rather than |
| 618 | // directly outputting to stderr here. |
| 619 | std.debug.print("{}", .{stderr_context.data.items}); |
| 620 | return error.LLDReportedFailure; |
| 621 | } |
| 622 | if (stderr_context.data.items.len != 0) { |
| 623 | std.log.warn("unexpected LLD stderr: {}", .{stderr_context.data.items}); |
| 624 | } |
| 603 | 625 | } |
| 604 | 626 | |
| 605 | 627 | if (!self.base.options.disable_lld_caching) { |