authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-23 17:38:03-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-23 17:38:03-04:00
log2614ef056a83842ec9501bf2e4f21ae840f981f8
tree94732cf3fd310a713907f8dd430b53843de9ee4a
parent7dbbddf2a693ba929ee164310dd73db1fa5d8df8

self-hosted: basic linker code for macos


5 files changed, 277 insertions(+), 8 deletions(-)

src-self-hosted/compilation.zig+1
......@@ -275,6 +275,7 @@ pub const Compilation = struct {
275275 LinkFailed,
276276 LibCRequiredButNotProvidedOrFound,
277277 LibCMissingDynamicLinker,
278 InvalidDarwinVersionString,
278279 };
279280
280281 pub const Event = union(enum) {
src-self-hosted/libc_installation.zig+1-5
......@@ -170,7 +170,7 @@ pub const LibCInstallation = struct {
170170 try group.call(findNativeDynamicLinker, self, loop);
171171 },
172172 builtin.Os.macosx => {
173 try group.call(findNativeIncludeDirMacOS, self, loop);
173 self.include_dir = try std.mem.dupe(loop.allocator, u8, "/usr/include");
174174 },
175175 else => @compileError("unimplemented: find libc for this OS"),
176176 }
......@@ -254,10 +254,6 @@ pub const LibCInstallation = struct {
254254 @panic("TODO");
255255 }
256256
257 async fn findNativeIncludeDirMacOS(self: *LibCInstallation, loop: *event.Loop) !void {
258 self.include_dir = try std.mem.dupe(loop.allocator, u8, "/usr/include");
259 }
260
261257 async fn findNativeLibDirWindows(self: *LibCInstallation, loop: *event.Loop) FindError!void {
262258 // TODO
263259 //ZigWindowsSDK *sdk = get_windows_sdk(g);
src-self-hosted/link.zig+241-2
......@@ -1,10 +1,12 @@
11const std = @import("std");
2const mem = std.mem;
23const c = @import("c.zig");
34const builtin = @import("builtin");
45const ObjectFormat = builtin.ObjectFormat;
56const Compilation = @import("compilation.zig").Compilation;
67const Target = @import("target.zig").Target;
78const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
9const assert = std.debug.assert;
810
911const Context = struct {
1012 comp: *Compilation,
......@@ -315,8 +317,163 @@ fn constructLinkerArgsCoff(ctx: *Context) void {
315317 @panic("TODO");
316318}
317319
318fn constructLinkerArgsMachO(ctx: *Context) void {
319 @panic("TODO");
320fn 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 //}
320477}
321478
322479fn constructLinkerArgsWasm(ctx: *Context) void {
......@@ -341,3 +498,85 @@ fn addFnObjects(ctx: *Context) !void {
341498 it = node.next;
342499 }
343500}
501
502const 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).
564fn 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}
src-self-hosted/target.zig+33
......@@ -526,4 +526,37 @@ pub const Target = union(enum) {
526526 => @panic("TODO specify the C integer type sizes for this OS"),
527527 }
528528 }
529
530 pub fn getDarwinArchString(self: Target) []const u8 {
531 const arch = self.getArch();
532 switch (arch) {
533 builtin.Arch.aarch64 => return "arm64",
534 builtin.Arch.thumb,
535 builtin.Arch.armv8_3a,
536 builtin.Arch.armv8_2a,
537 builtin.Arch.armv8_1a,
538 builtin.Arch.armv8,
539 builtin.Arch.armv8r,
540 builtin.Arch.armv8m_baseline,
541 builtin.Arch.armv8m_mainline,
542 builtin.Arch.armv7,
543 builtin.Arch.armv7em,
544 builtin.Arch.armv7m,
545 builtin.Arch.armv7s,
546 builtin.Arch.armv7k,
547 builtin.Arch.armv7ve,
548 builtin.Arch.armv6,
549 builtin.Arch.armv6m,
550 builtin.Arch.armv6k,
551 builtin.Arch.armv6t2,
552 builtin.Arch.armv5,
553 builtin.Arch.armv5te,
554 builtin.Arch.armv4t,
555 => return "arm",
556 builtin.Arch.powerpc => return "ppc",
557 builtin.Arch.powerpc64 => return "ppc64",
558 builtin.Arch.powerpc64le => return "ppc64le",
559 else => return @tagName(arch),
560 }
561 }
529562};
src/link.cpp+1-1
......@@ -901,7 +901,7 @@ static void construct_linker_job_macho(LinkJob *lj) {
901901 if (strchr(buf_ptr(link_lib->name), '/') == nullptr) {
902902 Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
903903 lj->args.append(buf_ptr(arg));
904 } else {
904 } else {
905905 lj->args.append(buf_ptr(link_lib->name));
906906 }
907907 }