self-hosted: basic linker code for macos
parent
7dbbddf2a6
commit
2614ef056a
|
@ -275,6 +275,7 @@ pub const Compilation = struct {
|
|||
LinkFailed,
|
||||
LibCRequiredButNotProvidedOrFound,
|
||||
LibCMissingDynamicLinker,
|
||||
InvalidDarwinVersionString,
|
||||
};
|
||||
|
||||
pub const Event = union(enum) {
|
||||
|
|
|
@ -170,7 +170,7 @@ pub const LibCInstallation = struct {
|
|||
try group.call(findNativeDynamicLinker, self, loop);
|
||||
},
|
||||
builtin.Os.macosx => {
|
||||
try group.call(findNativeIncludeDirMacOS, self, loop);
|
||||
self.include_dir = try std.mem.dupe(loop.allocator, u8, "/usr/include");
|
||||
},
|
||||
else => @compileError("unimplemented: find libc for this OS"),
|
||||
}
|
||||
|
@ -254,10 +254,6 @@ pub const LibCInstallation = struct {
|
|||
@panic("TODO");
|
||||
}
|
||||
|
||||
async fn findNativeIncludeDirMacOS(self: *LibCInstallation, loop: *event.Loop) !void {
|
||||
self.include_dir = try std.mem.dupe(loop.allocator, u8, "/usr/include");
|
||||
}
|
||||
|
||||
async fn findNativeLibDirWindows(self: *LibCInstallation, loop: *event.Loop) FindError!void {
|
||||
// TODO
|
||||
//ZigWindowsSDK *sdk = get_windows_sdk(g);
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const c = @import("c.zig");
|
||||
const builtin = @import("builtin");
|
||||
const ObjectFormat = builtin.ObjectFormat;
|
||||
const Compilation = @import("compilation.zig").Compilation;
|
||||
const Target = @import("target.zig").Target;
|
||||
const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
|
||||
const assert = std.debug.assert;
|
||||
|
||||
const Context = struct {
|
||||
comp: *Compilation,
|
||||
|
@ -315,8 +317,163 @@ fn constructLinkerArgsCoff(ctx: *Context) void {
|
|||
@panic("TODO");
|
||||
}
|
||||
|
||||
fn constructLinkerArgsMachO(ctx: *Context) void {
|
||||
fn constructLinkerArgsMachO(ctx: *Context) !void {
|
||||
try ctx.args.append(c"-demangle");
|
||||
|
||||
if (ctx.comp.linker_rdynamic) {
|
||||
try ctx.args.append(c"-export_dynamic");
|
||||
}
|
||||
|
||||
const is_lib = ctx.comp.kind == Compilation.Kind.Lib;
|
||||
const shared = !ctx.comp.is_static and is_lib;
|
||||
if (ctx.comp.is_static) {
|
||||
try ctx.args.append(c"-static");
|
||||
} else {
|
||||
try ctx.args.append(c"-dynamic");
|
||||
}
|
||||
|
||||
//if (is_lib) {
|
||||
// if (!g->is_static) {
|
||||
// lj->args.append("-dylib");
|
||||
|
||||
// Buf *compat_vers = buf_sprintf("%" ZIG_PRI_usize ".0.0", g->version_major);
|
||||
// lj->args.append("-compatibility_version");
|
||||
// lj->args.append(buf_ptr(compat_vers));
|
||||
|
||||
// Buf *cur_vers = buf_sprintf("%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize,
|
||||
// g->version_major, g->version_minor, g->version_patch);
|
||||
// lj->args.append("-current_version");
|
||||
// lj->args.append(buf_ptr(cur_vers));
|
||||
|
||||
// // TODO getting an error when running an executable when doing this rpath thing
|
||||
// //Buf *dylib_install_name = buf_sprintf("@rpath/lib%s.%" ZIG_PRI_usize ".dylib",
|
||||
// // buf_ptr(g->root_out_name), g->version_major);
|
||||
// //lj->args.append("-install_name");
|
||||
// //lj->args.append(buf_ptr(dylib_install_name));
|
||||
|
||||
// if (buf_len(&lj->out_file) == 0) {
|
||||
// buf_appendf(&lj->out_file, "lib%s.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".dylib",
|
||||
// buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
try ctx.args.append(c"-arch");
|
||||
const darwin_arch_str = try std.cstr.addNullByte(
|
||||
&ctx.arena.allocator,
|
||||
ctx.comp.target.getDarwinArchString(),
|
||||
);
|
||||
try ctx.args.append(darwin_arch_str.ptr);
|
||||
|
||||
const platform = try DarwinPlatform.get(ctx.comp);
|
||||
switch (platform.kind) {
|
||||
DarwinPlatform.Kind.MacOS => try ctx.args.append(c"-macosx_version_min"),
|
||||
DarwinPlatform.Kind.IPhoneOS => try ctx.args.append(c"-iphoneos_version_min"),
|
||||
DarwinPlatform.Kind.IPhoneOSSimulator => try ctx.args.append(c"-ios_simulator_version_min"),
|
||||
}
|
||||
const ver_str = try std.fmt.allocPrint(&ctx.arena.allocator, "{}.{}.{}\x00", platform.major, platform.minor, platform.micro);
|
||||
try ctx.args.append(ver_str.ptr);
|
||||
|
||||
if (ctx.comp.kind == Compilation.Kind.Exe) {
|
||||
if (ctx.comp.is_static) {
|
||||
try ctx.args.append(c"-no_pie");
|
||||
} else {
|
||||
try ctx.args.append(c"-pie");
|
||||
}
|
||||
}
|
||||
|
||||
try ctx.args.append(c"-o");
|
||||
try ctx.args.append(ctx.out_file_path.ptr());
|
||||
|
||||
//for (size_t i = 0; i < g->rpath_list.length; i += 1) {
|
||||
// Buf *rpath = g->rpath_list.at(i);
|
||||
// add_rpath(lj, rpath);
|
||||
//}
|
||||
//add_rpath(lj, &lj->out_file);
|
||||
|
||||
if (shared) {
|
||||
try ctx.args.append(c"-headerpad_max_install_names");
|
||||
} else if (ctx.comp.is_static) {
|
||||
try ctx.args.append(c"-lcrt0.o");
|
||||
} else {
|
||||
switch (platform.kind) {
|
||||
DarwinPlatform.Kind.MacOS => {
|
||||
if (platform.versionLessThan(10, 5)) {
|
||||
try ctx.args.append(c"-lcrt1.o");
|
||||
} else if (platform.versionLessThan(10, 6)) {
|
||||
try ctx.args.append(c"-lcrt1.10.5.o");
|
||||
} else if (platform.versionLessThan(10, 8)) {
|
||||
try ctx.args.append(c"-lcrt1.10.6.o");
|
||||
}
|
||||
},
|
||||
DarwinPlatform.Kind.IPhoneOS => {
|
||||
if (ctx.comp.target.getArch() == builtin.Arch.aarch64) {
|
||||
// iOS does not need any crt1 files for arm64
|
||||
} else if (platform.versionLessThan(3, 1)) {
|
||||
try ctx.args.append(c"-lcrt1.o");
|
||||
} else if (platform.versionLessThan(6, 0)) {
|
||||
try ctx.args.append(c"-lcrt1.3.1.o");
|
||||
}
|
||||
},
|
||||
DarwinPlatform.Kind.IPhoneOSSimulator => {}, // no crt1.o needed
|
||||
}
|
||||
}
|
||||
|
||||
//for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
|
||||
// const char *lib_dir = g->lib_dirs.at(i);
|
||||
// lj->args.append("-L");
|
||||
// lj->args.append(lib_dir);
|
||||
//}
|
||||
|
||||
for (ctx.comp.link_objects) |link_object| {
|
||||
const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object);
|
||||
try ctx.args.append(link_obj_with_null.ptr);
|
||||
}
|
||||
try addFnObjects(ctx);
|
||||
|
||||
//// compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce
|
||||
//if (g->out_type == OutTypeExe || g->out_type == OutTypeLib) {
|
||||
// Buf *compiler_rt_o_path = build_compiler_rt(g);
|
||||
// lj->args.append(buf_ptr(compiler_rt_o_path));
|
||||
//}
|
||||
|
||||
if (ctx.comp.target == Target.Native) {
|
||||
for (ctx.comp.link_libs_list.toSliceConst()) |lib| {
|
||||
if (mem.eql(u8, lib.name, "c")) {
|
||||
// on Darwin, libSystem has libc in it, but also you have to use it
|
||||
// to make syscalls because the syscall numbers are not documented
|
||||
// and change between versions.
|
||||
// so we always link against libSystem
|
||||
try ctx.args.append(c"-lSystem");
|
||||
} else {
|
||||
if (mem.indexOfScalar(u8, lib.name, '/') == null) {
|
||||
const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", lib.name);
|
||||
try ctx.args.append(arg.ptr);
|
||||
} else {
|
||||
const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name);
|
||||
try ctx.args.append(arg.ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try ctx.args.append(c"-undefined");
|
||||
try ctx.args.append(c"dynamic_lookup");
|
||||
}
|
||||
|
||||
if (platform.kind == DarwinPlatform.Kind.MacOS) {
|
||||
if (platform.versionLessThan(10, 5)) {
|
||||
try ctx.args.append(c"-lgcc_s.10.4");
|
||||
} else if (platform.versionLessThan(10, 6)) {
|
||||
try ctx.args.append(c"-lgcc_s.10.5");
|
||||
}
|
||||
} else {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
//for (size_t i = 0; i < g->darwin_frameworks.length; i += 1) {
|
||||
// lj->args.append("-framework");
|
||||
// lj->args.append(buf_ptr(g->darwin_frameworks.at(i)));
|
||||
//}
|
||||
}
|
||||
|
||||
fn constructLinkerArgsWasm(ctx: *Context) void {
|
||||
|
@ -341,3 +498,85 @@ fn addFnObjects(ctx: *Context) !void {
|
|||
it = node.next;
|
||||
}
|
||||
}
|
||||
|
||||
const DarwinPlatform = struct {
|
||||
kind: Kind,
|
||||
major: u32,
|
||||
minor: u32,
|
||||
micro: u32,
|
||||
|
||||
const Kind = enum {
|
||||
MacOS,
|
||||
IPhoneOS,
|
||||
IPhoneOSSimulator,
|
||||
};
|
||||
|
||||
fn get(comp: *Compilation) !DarwinPlatform {
|
||||
var result: DarwinPlatform = undefined;
|
||||
const ver_str = switch (comp.darwin_version_min) {
|
||||
Compilation.DarwinVersionMin.MacOS => |ver| blk: {
|
||||
result.kind = Kind.MacOS;
|
||||
break :blk ver;
|
||||
},
|
||||
Compilation.DarwinVersionMin.Ios => |ver| blk: {
|
||||
result.kind = Kind.IPhoneOS;
|
||||
break :blk ver;
|
||||
},
|
||||
Compilation.DarwinVersionMin.None => blk: {
|
||||
assert(comp.target.getOs() == builtin.Os.macosx);
|
||||
result.kind = Kind.MacOS;
|
||||
break :blk "10.10";
|
||||
},
|
||||
};
|
||||
|
||||
var had_extra: bool = undefined;
|
||||
try darwinGetReleaseVersion(ver_str, &result.major, &result.minor, &result.micro, &had_extra,);
|
||||
if (had_extra or result.major != 10 or result.minor >= 100 or result.micro >= 100) {
|
||||
return error.InvalidDarwinVersionString;
|
||||
}
|
||||
|
||||
if (result.kind == Kind.IPhoneOS) {
|
||||
switch (comp.target.getArch()) {
|
||||
builtin.Arch.i386,
|
||||
builtin.Arch.x86_64,
|
||||
=> result.kind = Kind.IPhoneOSSimulator,
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn versionLessThan(self: DarwinPlatform, major: u32, minor: u32) bool {
|
||||
if (self.major < major)
|
||||
return true;
|
||||
if (self.major > major)
|
||||
return false;
|
||||
if (self.minor < minor)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/// Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and return the
|
||||
/// grouped values as integers. Numbers which are not provided are set to 0.
|
||||
/// return true if the entire string was parsed (9.2), or all groups were
|
||||
/// parsed (10.3.5extrastuff).
|
||||
fn darwinGetReleaseVersion(str: []const u8, major: *u32, minor: *u32, micro: *u32, had_extra: *bool) !void {
|
||||
major.* = 0;
|
||||
minor.* = 0;
|
||||
micro.* = 0;
|
||||
had_extra.* = false;
|
||||
|
||||
if (str.len == 0)
|
||||
return error.InvalidDarwinVersionString;
|
||||
|
||||
var start_pos: usize = 0;
|
||||
for ([]*u32{major, minor, micro}) |v| {
|
||||
const dot_pos = mem.indexOfScalarPos(u8, str, start_pos, '.');
|
||||
const end_pos = dot_pos orelse str.len;
|
||||
v.* = std.fmt.parseUnsigned(u32, str[start_pos..end_pos], 10) catch return error.InvalidDarwinVersionString;
|
||||
start_pos = (dot_pos orelse return) + 1;
|
||||
if (start_pos == str.len) return;
|
||||
}
|
||||
had_extra.* = true;
|
||||
}
|
||||
|
|
|
@ -526,4 +526,37 @@ pub const Target = union(enum) {
|
|||
=> @panic("TODO specify the C integer type sizes for this OS"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getDarwinArchString(self: Target) []const u8 {
|
||||
const arch = self.getArch();
|
||||
switch (arch) {
|
||||
builtin.Arch.aarch64 => return "arm64",
|
||||
builtin.Arch.thumb,
|
||||
builtin.Arch.armv8_3a,
|
||||
builtin.Arch.armv8_2a,
|
||||
builtin.Arch.armv8_1a,
|
||||
builtin.Arch.armv8,
|
||||
builtin.Arch.armv8r,
|
||||
builtin.Arch.armv8m_baseline,
|
||||
builtin.Arch.armv8m_mainline,
|
||||
builtin.Arch.armv7,
|
||||
builtin.Arch.armv7em,
|
||||
builtin.Arch.armv7m,
|
||||
builtin.Arch.armv7s,
|
||||
builtin.Arch.armv7k,
|
||||
builtin.Arch.armv7ve,
|
||||
builtin.Arch.armv6,
|
||||
builtin.Arch.armv6m,
|
||||
builtin.Arch.armv6k,
|
||||
builtin.Arch.armv6t2,
|
||||
builtin.Arch.armv5,
|
||||
builtin.Arch.armv5te,
|
||||
builtin.Arch.armv4t,
|
||||
=> return "arm",
|
||||
builtin.Arch.powerpc => return "ppc",
|
||||
builtin.Arch.powerpc64 => return "ppc64",
|
||||
builtin.Arch.powerpc64le => return "ppc64le",
|
||||
else => return @tagName(arch),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue