| ... | ... | @@ -1,10 +1,12 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const mem = std.mem; |
| 2 | 3 | const c = @import("c.zig"); |
| 3 | 4 | const builtin = @import("builtin"); |
| 4 | 5 | const ObjectFormat = builtin.ObjectFormat; |
| 5 | 6 | const Compilation = @import("compilation.zig").Compilation; |
| 6 | 7 | const Target = @import("target.zig").Target; |
| 7 | 8 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; |
| 9 | const assert = std.debug.assert; |
| 8 | 10 | |
| 9 | 11 | const Context = struct { |
| 10 | 12 | comp: *Compilation, |
| ... | ... | @@ -315,8 +317,163 @@ fn constructLinkerArgsCoff(ctx: *Context) void { |
| 315 | 317 | @panic("TODO"); |
| 316 | 318 | } |
| 317 | 319 | |
| 318 | | fn constructLinkerArgsMachO(ctx: *Context) void { |
| 319 | | @panic("TODO"); |
| 320 | fn constructLinkerArgsMachO(ctx: *Context) !void { |
| 321 | try ctx.args.append(c"-demangle"); |
| 322 | |
| 323 | if (ctx.comp.linker_rdynamic) { |
| 324 | try ctx.args.append(c"-export_dynamic"); |
| 325 | } |
| 326 | |
| 327 | const is_lib = ctx.comp.kind == Compilation.Kind.Lib; |
| 328 | const shared = !ctx.comp.is_static and is_lib; |
| 329 | if (ctx.comp.is_static) { |
| 330 | try ctx.args.append(c"-static"); |
| 331 | } else { |
| 332 | try ctx.args.append(c"-dynamic"); |
| 333 | } |
| 334 | |
| 335 | //if (is_lib) { |
| 336 | // if (!g->is_static) { |
| 337 | // lj->args.append("-dylib"); |
| 338 | |
| 339 | // Buf *compat_vers = buf_sprintf("%" ZIG_PRI_usize ".0.0", g->version_major); |
| 340 | // lj->args.append("-compatibility_version"); |
| 341 | // lj->args.append(buf_ptr(compat_vers)); |
| 342 | |
| 343 | // Buf *cur_vers = buf_sprintf("%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize, |
| 344 | // g->version_major, g->version_minor, g->version_patch); |
| 345 | // lj->args.append("-current_version"); |
| 346 | // lj->args.append(buf_ptr(cur_vers)); |
| 347 | |
| 348 | // // TODO getting an error when running an executable when doing this rpath thing |
| 349 | // //Buf *dylib_install_name = buf_sprintf("@rpath/lib%s.%" ZIG_PRI_usize ".dylib", |
| 350 | // // buf_ptr(g->root_out_name), g->version_major); |
| 351 | // //lj->args.append("-install_name"); |
| 352 | // //lj->args.append(buf_ptr(dylib_install_name)); |
| 353 | |
| 354 | // if (buf_len(&lj->out_file) == 0) { |
| 355 | // buf_appendf(&lj->out_file, "lib%s.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".dylib", |
| 356 | // buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch); |
| 357 | // } |
| 358 | // } |
| 359 | //} |
| 360 | |
| 361 | try ctx.args.append(c"-arch"); |
| 362 | const darwin_arch_str = try std.cstr.addNullByte( |
| 363 | &ctx.arena.allocator, |
| 364 | ctx.comp.target.getDarwinArchString(), |
| 365 | ); |
| 366 | try ctx.args.append(darwin_arch_str.ptr); |
| 367 | |
| 368 | const platform = try DarwinPlatform.get(ctx.comp); |
| 369 | switch (platform.kind) { |
| 370 | DarwinPlatform.Kind.MacOS => try ctx.args.append(c"-macosx_version_min"), |
| 371 | DarwinPlatform.Kind.IPhoneOS => try ctx.args.append(c"-iphoneos_version_min"), |
| 372 | DarwinPlatform.Kind.IPhoneOSSimulator => try ctx.args.append(c"-ios_simulator_version_min"), |
| 373 | } |
| 374 | const ver_str = try std.fmt.allocPrint(&ctx.arena.allocator, "{}.{}.{}\x00", platform.major, platform.minor, platform.micro); |
| 375 | try ctx.args.append(ver_str.ptr); |
| 376 | |
| 377 | if (ctx.comp.kind == Compilation.Kind.Exe) { |
| 378 | if (ctx.comp.is_static) { |
| 379 | try ctx.args.append(c"-no_pie"); |
| 380 | } else { |
| 381 | try ctx.args.append(c"-pie"); |
| 382 | } |
| 383 | } |
| 384 | |
| 385 | try ctx.args.append(c"-o"); |
| 386 | try ctx.args.append(ctx.out_file_path.ptr()); |
| 387 | |
| 388 | //for (size_t i = 0; i < g->rpath_list.length; i += 1) { |
| 389 | // Buf *rpath = g->rpath_list.at(i); |
| 390 | // add_rpath(lj, rpath); |
| 391 | //} |
| 392 | //add_rpath(lj, &lj->out_file); |
| 393 | |
| 394 | if (shared) { |
| 395 | try ctx.args.append(c"-headerpad_max_install_names"); |
| 396 | } else if (ctx.comp.is_static) { |
| 397 | try ctx.args.append(c"-lcrt0.o"); |
| 398 | } else { |
| 399 | switch (platform.kind) { |
| 400 | DarwinPlatform.Kind.MacOS => { |
| 401 | if (platform.versionLessThan(10, 5)) { |
| 402 | try ctx.args.append(c"-lcrt1.o"); |
| 403 | } else if (platform.versionLessThan(10, 6)) { |
| 404 | try ctx.args.append(c"-lcrt1.10.5.o"); |
| 405 | } else if (platform.versionLessThan(10, 8)) { |
| 406 | try ctx.args.append(c"-lcrt1.10.6.o"); |
| 407 | } |
| 408 | }, |
| 409 | DarwinPlatform.Kind.IPhoneOS => { |
| 410 | if (ctx.comp.target.getArch() == builtin.Arch.aarch64) { |
| 411 | // iOS does not need any crt1 files for arm64 |
| 412 | } else if (platform.versionLessThan(3, 1)) { |
| 413 | try ctx.args.append(c"-lcrt1.o"); |
| 414 | } else if (platform.versionLessThan(6, 0)) { |
| 415 | try ctx.args.append(c"-lcrt1.3.1.o"); |
| 416 | } |
| 417 | }, |
| 418 | DarwinPlatform.Kind.IPhoneOSSimulator => {}, // no crt1.o needed |
| 419 | } |
| 420 | } |
| 421 | |
| 422 | //for (size_t i = 0; i < g->lib_dirs.length; i += 1) { |
| 423 | // const char *lib_dir = g->lib_dirs.at(i); |
| 424 | // lj->args.append("-L"); |
| 425 | // lj->args.append(lib_dir); |
| 426 | //} |
| 427 | |
| 428 | for (ctx.comp.link_objects) |link_object| { |
| 429 | const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object); |
| 430 | try ctx.args.append(link_obj_with_null.ptr); |
| 431 | } |
| 432 | try addFnObjects(ctx); |
| 433 | |
| 434 | //// compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce |
| 435 | //if (g->out_type == OutTypeExe || g->out_type == OutTypeLib) { |
| 436 | // Buf *compiler_rt_o_path = build_compiler_rt(g); |
| 437 | // lj->args.append(buf_ptr(compiler_rt_o_path)); |
| 438 | //} |
| 439 | |
| 440 | if (ctx.comp.target == Target.Native) { |
| 441 | for (ctx.comp.link_libs_list.toSliceConst()) |lib| { |
| 442 | if (mem.eql(u8, lib.name, "c")) { |
| 443 | // on Darwin, libSystem has libc in it, but also you have to use it |
| 444 | // to make syscalls because the syscall numbers are not documented |
| 445 | // and change between versions. |
| 446 | // so we always link against libSystem |
| 447 | try ctx.args.append(c"-lSystem"); |
| 448 | } else { |
| 449 | if (mem.indexOfScalar(u8, lib.name, '/') == null) { |
| 450 | const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", lib.name); |
| 451 | try ctx.args.append(arg.ptr); |
| 452 | } else { |
| 453 | const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name); |
| 454 | try ctx.args.append(arg.ptr); |
| 455 | } |
| 456 | } |
| 457 | } |
| 458 | } else { |
| 459 | try ctx.args.append(c"-undefined"); |
| 460 | try ctx.args.append(c"dynamic_lookup"); |
| 461 | } |
| 462 | |
| 463 | if (platform.kind == DarwinPlatform.Kind.MacOS) { |
| 464 | if (platform.versionLessThan(10, 5)) { |
| 465 | try ctx.args.append(c"-lgcc_s.10.4"); |
| 466 | } else if (platform.versionLessThan(10, 6)) { |
| 467 | try ctx.args.append(c"-lgcc_s.10.5"); |
| 468 | } |
| 469 | } else { |
| 470 | @panic("TODO"); |
| 471 | } |
| 472 | |
| 473 | //for (size_t i = 0; i < g->darwin_frameworks.length; i += 1) { |
| 474 | // lj->args.append("-framework"); |
| 475 | // lj->args.append(buf_ptr(g->darwin_frameworks.at(i))); |
| 476 | //} |
| 320 | 477 | } |
| 321 | 478 | |
| 322 | 479 | fn constructLinkerArgsWasm(ctx: *Context) void { |
| ... | ... | @@ -341,3 +498,85 @@ fn addFnObjects(ctx: *Context) !void { |
| 341 | 498 | it = node.next; |
| 342 | 499 | } |
| 343 | 500 | } |
| 501 | |
| 502 | const DarwinPlatform = struct { |
| 503 | kind: Kind, |
| 504 | major: u32, |
| 505 | minor: u32, |
| 506 | micro: u32, |
| 507 | |
| 508 | const Kind = enum { |
| 509 | MacOS, |
| 510 | IPhoneOS, |
| 511 | IPhoneOSSimulator, |
| 512 | }; |
| 513 | |
| 514 | fn get(comp: *Compilation) !DarwinPlatform { |
| 515 | var result: DarwinPlatform = undefined; |
| 516 | const ver_str = switch (comp.darwin_version_min) { |
| 517 | Compilation.DarwinVersionMin.MacOS => |ver| blk: { |
| 518 | result.kind = Kind.MacOS; |
| 519 | break :blk ver; |
| 520 | }, |
| 521 | Compilation.DarwinVersionMin.Ios => |ver| blk: { |
| 522 | result.kind = Kind.IPhoneOS; |
| 523 | break :blk ver; |
| 524 | }, |
| 525 | Compilation.DarwinVersionMin.None => blk: { |
| 526 | assert(comp.target.getOs() == builtin.Os.macosx); |
| 527 | result.kind = Kind.MacOS; |
| 528 | break :blk "10.10"; |
| 529 | }, |
| 530 | }; |
| 531 | |
| 532 | var had_extra: bool = undefined; |
| 533 | try darwinGetReleaseVersion(ver_str, &result.major, &result.minor, &result.micro, &had_extra,); |
| 534 | if (had_extra or result.major != 10 or result.minor >= 100 or result.micro >= 100) { |
| 535 | return error.InvalidDarwinVersionString; |
| 536 | } |
| 537 | |
| 538 | if (result.kind == Kind.IPhoneOS) { |
| 539 | switch (comp.target.getArch()) { |
| 540 | builtin.Arch.i386, |
| 541 | builtin.Arch.x86_64, |
| 542 | => result.kind = Kind.IPhoneOSSimulator, |
| 543 | else => {}, |
| 544 | } |
| 545 | } |
| 546 | return result; |
| 547 | } |
| 548 | |
| 549 | fn versionLessThan(self: DarwinPlatform, major: u32, minor: u32) bool { |
| 550 | if (self.major < major) |
| 551 | return true; |
| 552 | if (self.major > major) |
| 553 | return false; |
| 554 | if (self.minor < minor) |
| 555 | return true; |
| 556 | return false; |
| 557 | } |
| 558 | }; |
| 559 | |
| 560 | /// Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and return the |
| 561 | /// grouped values as integers. Numbers which are not provided are set to 0. |
| 562 | /// return true if the entire string was parsed (9.2), or all groups were |
| 563 | /// parsed (10.3.5extrastuff). |
| 564 | fn darwinGetReleaseVersion(str: []const u8, major: *u32, minor: *u32, micro: *u32, had_extra: *bool) !void { |
| 565 | major.* = 0; |
| 566 | minor.* = 0; |
| 567 | micro.* = 0; |
| 568 | had_extra.* = false; |
| 569 | |
| 570 | if (str.len == 0) |
| 571 | return error.InvalidDarwinVersionString; |
| 572 | |
| 573 | var start_pos: usize = 0; |
| 574 | for ([]*u32{major, minor, micro}) |v| { |
| 575 | const dot_pos = mem.indexOfScalarPos(u8, str, start_pos, '.'); |
| 576 | const end_pos = dot_pos orelse str.len; |
| 577 | v.* = std.fmt.parseUnsigned(u32, str[start_pos..end_pos], 10) catch return error.InvalidDarwinVersionString; |
| 578 | start_pos = (dot_pos orelse return) + 1; |
| 579 | if (start_pos == str.len) return; |
| 580 | } |
| 581 | had_extra.* = true; |
| 582 | } |