mirror of
https://github.com/ziglang/zig.git
synced 2026-01-31 11:43:37 +00:00
this also deletes C string literals from the language, and then makes the std lib changes and compiler changes necessary to get the behavior tests and std lib tests passing again.
734 lines
27 KiB
Zig
734 lines
27 KiB
Zig
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,
|
|
arena: std.heap.ArenaAllocator,
|
|
args: std.ArrayList([*]const u8),
|
|
link_in_crt: bool,
|
|
|
|
link_err: error{OutOfMemory}!void,
|
|
link_msg: std.Buffer,
|
|
|
|
libc: *LibCInstallation,
|
|
out_file_path: std.Buffer,
|
|
};
|
|
|
|
pub async fn link(comp: *Compilation) !void {
|
|
var ctx = Context{
|
|
.comp = comp,
|
|
.arena = std.heap.ArenaAllocator.init(comp.gpa()),
|
|
.args = undefined,
|
|
.link_in_crt = comp.haveLibC() and comp.kind == Compilation.Kind.Exe,
|
|
.link_err = {},
|
|
.link_msg = undefined,
|
|
.libc = undefined,
|
|
.out_file_path = undefined,
|
|
};
|
|
defer ctx.arena.deinit();
|
|
ctx.args = std.ArrayList([*]const u8).init(&ctx.arena.allocator);
|
|
ctx.link_msg = std.Buffer.initNull(&ctx.arena.allocator);
|
|
|
|
if (comp.link_out_file) |out_file| {
|
|
ctx.out_file_path = try std.Buffer.init(&ctx.arena.allocator, out_file);
|
|
} else {
|
|
ctx.out_file_path = try std.Buffer.init(&ctx.arena.allocator, comp.name.toSliceConst());
|
|
switch (comp.kind) {
|
|
Compilation.Kind.Exe => {
|
|
try ctx.out_file_path.append(comp.target.exeFileExt());
|
|
},
|
|
Compilation.Kind.Lib => {
|
|
try ctx.out_file_path.append(comp.target.libFileExt(comp.is_static));
|
|
},
|
|
Compilation.Kind.Obj => {
|
|
try ctx.out_file_path.append(comp.target.objFileExt());
|
|
},
|
|
}
|
|
}
|
|
|
|
// even though we're calling LLD as a library it thinks the first
|
|
// argument is its own exe name
|
|
try ctx.args.append("lld");
|
|
|
|
if (comp.haveLibC()) {
|
|
ctx.libc = ctx.comp.override_libc orelse blk: {
|
|
switch (comp.target) {
|
|
Target.Native => {
|
|
break :blk (await (async comp.zig_compiler.getNativeLibC() catch unreachable)) catch return error.LibCRequiredButNotProvidedOrFound;
|
|
},
|
|
else => return error.LibCRequiredButNotProvidedOrFound,
|
|
}
|
|
};
|
|
}
|
|
|
|
try constructLinkerArgs(&ctx);
|
|
|
|
if (comp.verbose_link) {
|
|
for (ctx.args.toSliceConst()) |arg, i| {
|
|
const space = if (i == 0) "" else " ";
|
|
std.debug.warn("{}{s}", space, arg);
|
|
}
|
|
std.debug.warn("\n");
|
|
}
|
|
|
|
const extern_ofmt = toExternObjectFormatType(comp.target.getObjectFormat());
|
|
const args_slice = ctx.args.toSlice();
|
|
|
|
{
|
|
// LLD is not thread-safe, so we grab a global lock.
|
|
const held = await (async comp.zig_compiler.lld_lock.acquire() catch unreachable);
|
|
defer held.release();
|
|
|
|
// Not evented I/O. LLD does its own multithreading internally.
|
|
if (!ZigLLDLink(extern_ofmt, args_slice.ptr, args_slice.len, linkDiagCallback, @ptrCast(*c_void, &ctx))) {
|
|
if (!ctx.link_msg.isNull()) {
|
|
// TODO capture these messages and pass them through the system, reporting them through the
|
|
// event system instead of printing them directly here.
|
|
// perhaps try to parse and understand them.
|
|
std.debug.warn("{}\n", ctx.link_msg.toSliceConst());
|
|
}
|
|
return error.LinkFailed;
|
|
}
|
|
}
|
|
}
|
|
|
|
extern fn ZigLLDLink(
|
|
oformat: c.ZigLLVM_ObjectFormatType,
|
|
args: [*]const [*]const u8,
|
|
arg_count: usize,
|
|
append_diagnostic: extern fn (*c_void, [*]const u8, usize) void,
|
|
context: *c_void,
|
|
) bool;
|
|
|
|
extern fn linkDiagCallback(context: *c_void, ptr: [*]const u8, len: usize) void {
|
|
const ctx = @ptrCast(*Context, @alignCast(@alignOf(Context), context));
|
|
ctx.link_err = linkDiagCallbackErrorable(ctx, ptr[0..len]);
|
|
}
|
|
|
|
fn linkDiagCallbackErrorable(ctx: *Context, msg: []const u8) !void {
|
|
if (ctx.link_msg.isNull()) {
|
|
try ctx.link_msg.resize(0);
|
|
}
|
|
try ctx.link_msg.append(msg);
|
|
}
|
|
|
|
fn toExternObjectFormatType(ofmt: ObjectFormat) c.ZigLLVM_ObjectFormatType {
|
|
return switch (ofmt) {
|
|
ObjectFormat.unknown => c.ZigLLVM_UnknownObjectFormat,
|
|
ObjectFormat.coff => c.ZigLLVM_COFF,
|
|
ObjectFormat.elf => c.ZigLLVM_ELF,
|
|
ObjectFormat.macho => c.ZigLLVM_MachO,
|
|
ObjectFormat.wasm => c.ZigLLVM_Wasm,
|
|
};
|
|
}
|
|
|
|
fn constructLinkerArgs(ctx: *Context) !void {
|
|
switch (ctx.comp.target.getObjectFormat()) {
|
|
ObjectFormat.unknown => unreachable,
|
|
ObjectFormat.coff => return constructLinkerArgsCoff(ctx),
|
|
ObjectFormat.elf => return constructLinkerArgsElf(ctx),
|
|
ObjectFormat.macho => return constructLinkerArgsMachO(ctx),
|
|
ObjectFormat.wasm => return constructLinkerArgsWasm(ctx),
|
|
}
|
|
}
|
|
|
|
fn constructLinkerArgsElf(ctx: *Context) !void {
|
|
// TODO commented out code in this function
|
|
//if (g->linker_script) {
|
|
// lj->args.append("-T");
|
|
// lj->args.append(g->linker_script);
|
|
//}
|
|
try ctx.args.append("--gc-sections");
|
|
|
|
//lj->args.append("-m");
|
|
//lj->args.append(getLDMOption(&g->zig_target));
|
|
|
|
//bool is_lib = g->out_type == OutTypeLib;
|
|
//bool shared = !g->is_static && is_lib;
|
|
//Buf *soname = nullptr;
|
|
if (ctx.comp.is_static) {
|
|
if (ctx.comp.target.isArmOrThumb()) {
|
|
try ctx.args.append("-Bstatic");
|
|
} else {
|
|
try ctx.args.append("-static");
|
|
}
|
|
}
|
|
//} else if (shared) {
|
|
// lj->args.append("-shared");
|
|
|
|
// if (buf_len(&lj->out_file) == 0) {
|
|
// buf_appendf(&lj->out_file, "lib%s.so.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize "",
|
|
// buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch);
|
|
// }
|
|
// soname = buf_sprintf("lib%s.so.%" ZIG_PRI_usize "", buf_ptr(g->root_out_name), g->version_major);
|
|
//}
|
|
|
|
try ctx.args.append("-o");
|
|
try ctx.args.append(ctx.out_file_path.ptr());
|
|
|
|
if (ctx.link_in_crt) {
|
|
const crt1o = if (ctx.comp.is_static) "crt1.o" else "Scrt1.o";
|
|
const crtbegino = if (ctx.comp.is_static) "crtbeginT.o" else "crtbegin.o";
|
|
try addPathJoin(ctx, ctx.libc.lib_dir.?, crt1o);
|
|
try addPathJoin(ctx, ctx.libc.lib_dir.?, "crti.o");
|
|
try addPathJoin(ctx, ctx.libc.static_lib_dir.?, crtbegino);
|
|
}
|
|
|
|
//for (size_t i = 0; i < g->rpath_list.length; i += 1) {
|
|
// Buf *rpath = g->rpath_list.at(i);
|
|
// add_rpath(lj, rpath);
|
|
//}
|
|
//if (g->each_lib_rpath) {
|
|
// for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
|
|
// const char *lib_dir = g->lib_dirs.at(i);
|
|
// for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
|
|
// LinkLib *link_lib = g->link_libs_list.at(i);
|
|
// if (buf_eql_str(link_lib->name, "c")) {
|
|
// continue;
|
|
// }
|
|
// bool does_exist;
|
|
// Buf *test_path = buf_sprintf("%s/lib%s.so", lib_dir, buf_ptr(link_lib->name));
|
|
// if (os_file_exists(test_path, &does_exist) != ErrorNone) {
|
|
// zig_panic("link: unable to check if file exists: %s", buf_ptr(test_path));
|
|
// }
|
|
// if (does_exist) {
|
|
// add_rpath(lj, buf_create_from_str(lib_dir));
|
|
// break;
|
|
// }
|
|
// }
|
|
// }
|
|
//}
|
|
|
|
//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);
|
|
//}
|
|
|
|
if (ctx.comp.haveLibC()) {
|
|
try ctx.args.append("-L");
|
|
try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.lib_dir.?)).ptr);
|
|
|
|
try ctx.args.append("-L");
|
|
try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.static_lib_dir.?)).ptr);
|
|
|
|
if (!ctx.comp.is_static) {
|
|
const dl = blk: {
|
|
if (ctx.libc.dynamic_linker_path) |dl| break :blk dl;
|
|
if (ctx.comp.target.getDynamicLinkerPath()) |dl| break :blk dl;
|
|
return error.LibCMissingDynamicLinker;
|
|
};
|
|
try ctx.args.append("-dynamic-linker");
|
|
try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr);
|
|
}
|
|
}
|
|
|
|
//if (shared) {
|
|
// lj->args.append("-soname");
|
|
// lj->args.append(buf_ptr(soname));
|
|
//}
|
|
|
|
// .o files
|
|
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);
|
|
|
|
//if (g->out_type == OutTypeExe || g->out_type == OutTypeLib) {
|
|
// if (g->libc_link_lib == nullptr) {
|
|
// Buf *builtin_o_path = build_o(g, "builtin");
|
|
// lj->args.append(buf_ptr(builtin_o_path));
|
|
// }
|
|
|
|
// // sometimes libgcc is missing stuff, so we still build compiler_rt and rely on weak linkage
|
|
// Buf *compiler_rt_o_path = build_compiler_rt(g);
|
|
// lj->args.append(buf_ptr(compiler_rt_o_path));
|
|
//}
|
|
|
|
//for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
|
|
// LinkLib *link_lib = g->link_libs_list.at(i);
|
|
// if (buf_eql_str(link_lib->name, "c")) {
|
|
// continue;
|
|
// }
|
|
// Buf *arg;
|
|
// if (buf_starts_with_str(link_lib->name, "/") || buf_ends_with_str(link_lib->name, ".a") ||
|
|
// buf_ends_with_str(link_lib->name, ".so"))
|
|
// {
|
|
// arg = link_lib->name;
|
|
// } else {
|
|
// arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
|
|
// }
|
|
// lj->args.append(buf_ptr(arg));
|
|
//}
|
|
|
|
// libc dep
|
|
if (ctx.comp.haveLibC()) {
|
|
if (ctx.comp.is_static) {
|
|
try ctx.args.append("--start-group");
|
|
try ctx.args.append("-lgcc");
|
|
try ctx.args.append("-lgcc_eh");
|
|
try ctx.args.append("-lc");
|
|
try ctx.args.append("-lm");
|
|
try ctx.args.append("--end-group");
|
|
} else {
|
|
try ctx.args.append("-lgcc");
|
|
try ctx.args.append("--as-needed");
|
|
try ctx.args.append("-lgcc_s");
|
|
try ctx.args.append("--no-as-needed");
|
|
try ctx.args.append("-lc");
|
|
try ctx.args.append("-lm");
|
|
try ctx.args.append("-lgcc");
|
|
try ctx.args.append("--as-needed");
|
|
try ctx.args.append("-lgcc_s");
|
|
try ctx.args.append("--no-as-needed");
|
|
}
|
|
}
|
|
|
|
// crt end
|
|
if (ctx.link_in_crt) {
|
|
try addPathJoin(ctx, ctx.libc.static_lib_dir.?, "crtend.o");
|
|
try addPathJoin(ctx, ctx.libc.lib_dir.?, "crtn.o");
|
|
}
|
|
|
|
if (ctx.comp.target != Target.Native) {
|
|
try ctx.args.append("--allow-shlib-undefined");
|
|
}
|
|
|
|
if (ctx.comp.target.getOs() == .zen) {
|
|
try ctx.args.append("-e");
|
|
try ctx.args.append("_start");
|
|
|
|
try ctx.args.append("--image-base=0x10000000");
|
|
}
|
|
}
|
|
|
|
fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void {
|
|
const full_path = try std.fs.path.join(&ctx.arena.allocator, [_][]const u8{ dirname, basename });
|
|
const full_path_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, full_path);
|
|
try ctx.args.append(full_path_with_null.ptr);
|
|
}
|
|
|
|
fn constructLinkerArgsCoff(ctx: *Context) !void {
|
|
try ctx.args.append("-NOLOGO");
|
|
|
|
if (!ctx.comp.strip) {
|
|
try ctx.args.append("-DEBUG");
|
|
}
|
|
|
|
switch (ctx.comp.target.getArch()) {
|
|
builtin.Arch.i386 => try ctx.args.append("-MACHINE:X86"),
|
|
builtin.Arch.x86_64 => try ctx.args.append("-MACHINE:X64"),
|
|
builtin.Arch.aarch64 => try ctx.args.append("-MACHINE:ARM"),
|
|
else => return error.UnsupportedLinkArchitecture,
|
|
}
|
|
|
|
if (ctx.comp.windows_subsystem_windows) {
|
|
try ctx.args.append("/SUBSYSTEM:windows");
|
|
} else if (ctx.comp.windows_subsystem_console) {
|
|
try ctx.args.append("/SUBSYSTEM:console");
|
|
}
|
|
|
|
const is_library = ctx.comp.kind == Compilation.Kind.Lib;
|
|
|
|
const out_arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-OUT:{}\x00", ctx.out_file_path.toSliceConst());
|
|
try ctx.args.append(out_arg.ptr);
|
|
|
|
if (ctx.comp.haveLibC()) {
|
|
try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.msvc_lib_dir.?)).ptr);
|
|
try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.kernel32_lib_dir.?)).ptr);
|
|
try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.lib_dir.?)).ptr);
|
|
}
|
|
|
|
if (ctx.link_in_crt) {
|
|
const lib_str = if (ctx.comp.is_static) "lib" else "";
|
|
const d_str = if (ctx.comp.build_mode == builtin.Mode.Debug) "d" else "";
|
|
|
|
if (ctx.comp.is_static) {
|
|
const cmt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "libcmt{}.lib\x00", d_str);
|
|
try ctx.args.append(cmt_lib_name.ptr);
|
|
} else {
|
|
const msvcrt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "msvcrt{}.lib\x00", d_str);
|
|
try ctx.args.append(msvcrt_lib_name.ptr);
|
|
}
|
|
|
|
const vcruntime_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}vcruntime{}.lib\x00", lib_str, d_str);
|
|
try ctx.args.append(vcruntime_lib_name.ptr);
|
|
|
|
const crt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}ucrt{}.lib\x00", lib_str, d_str);
|
|
try ctx.args.append(crt_lib_name.ptr);
|
|
|
|
// Visual C++ 2015 Conformance Changes
|
|
// https://msdn.microsoft.com/en-us/library/bb531344.aspx
|
|
try ctx.args.append("legacy_stdio_definitions.lib");
|
|
|
|
// msvcrt depends on kernel32
|
|
try ctx.args.append("kernel32.lib");
|
|
} else {
|
|
try ctx.args.append("-NODEFAULTLIB");
|
|
if (!is_library) {
|
|
try ctx.args.append("-ENTRY:WinMainCRTStartup");
|
|
// TODO
|
|
//if (g->have_winmain) {
|
|
// lj->args.append("-ENTRY:WinMain");
|
|
//} else {
|
|
// lj->args.append("-ENTRY:WinMainCRTStartup");
|
|
//}
|
|
}
|
|
}
|
|
|
|
if (is_library and !ctx.comp.is_static) {
|
|
try ctx.args.append("-DLL");
|
|
}
|
|
|
|
//for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
|
|
// const char *lib_dir = g->lib_dirs.at(i);
|
|
// lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", 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);
|
|
|
|
switch (ctx.comp.kind) {
|
|
Compilation.Kind.Exe, Compilation.Kind.Lib => {
|
|
if (!ctx.comp.haveLibC()) {
|
|
@panic("TODO");
|
|
//Buf *builtin_o_path = build_o(g, "builtin");
|
|
//lj->args.append(buf_ptr(builtin_o_path));
|
|
}
|
|
|
|
// msvc compiler_rt is missing some stuff, so we still build it and rely on weak linkage
|
|
// TODO
|
|
//Buf *compiler_rt_o_path = build_compiler_rt(g);
|
|
//lj->args.append(buf_ptr(compiler_rt_o_path));
|
|
},
|
|
Compilation.Kind.Obj => {},
|
|
}
|
|
|
|
//Buf *def_contents = buf_alloc();
|
|
//ZigList<const char *> gen_lib_args = {0};
|
|
//for (size_t lib_i = 0; lib_i < g->link_libs_list.length; lib_i += 1) {
|
|
// LinkLib *link_lib = g->link_libs_list.at(lib_i);
|
|
// if (buf_eql_str(link_lib->name, "c")) {
|
|
// continue;
|
|
// }
|
|
// if (link_lib->provided_explicitly) {
|
|
// if (lj->codegen->zig_target.env_type == ZigLLVM_GNU) {
|
|
// Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
|
|
// lj->args.append(buf_ptr(arg));
|
|
// }
|
|
// else {
|
|
// lj->args.append(buf_ptr(link_lib->name));
|
|
// }
|
|
// } else {
|
|
// buf_resize(def_contents, 0);
|
|
// buf_appendf(def_contents, "LIBRARY %s\nEXPORTS\n", buf_ptr(link_lib->name));
|
|
// for (size_t exp_i = 0; exp_i < link_lib->symbols.length; exp_i += 1) {
|
|
// Buf *symbol_name = link_lib->symbols.at(exp_i);
|
|
// buf_appendf(def_contents, "%s\n", buf_ptr(symbol_name));
|
|
// }
|
|
// buf_appendf(def_contents, "\n");
|
|
|
|
// Buf *def_path = buf_alloc();
|
|
// os_path_join(g->cache_dir, buf_sprintf("%s.def", buf_ptr(link_lib->name)), def_path);
|
|
// os_write_file(def_path, def_contents);
|
|
|
|
// Buf *generated_lib_path = buf_alloc();
|
|
// os_path_join(g->cache_dir, buf_sprintf("%s.lib", buf_ptr(link_lib->name)), generated_lib_path);
|
|
|
|
// gen_lib_args.resize(0);
|
|
// gen_lib_args.append("link");
|
|
|
|
// coff_append_machine_arg(g, &gen_lib_args);
|
|
// gen_lib_args.append(buf_ptr(buf_sprintf("-DEF:%s", buf_ptr(def_path))));
|
|
// gen_lib_args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(generated_lib_path))));
|
|
// Buf diag = BUF_INIT;
|
|
// if (!zig_lld_link(g->zig_target.oformat, gen_lib_args.items, gen_lib_args.length, &diag)) {
|
|
// fprintf(stderr, "%s\n", buf_ptr(&diag));
|
|
// exit(1);
|
|
// }
|
|
// lj->args.append(buf_ptr(generated_lib_path));
|
|
// }
|
|
//}
|
|
}
|
|
|
|
fn constructLinkerArgsMachO(ctx: *Context) !void {
|
|
try ctx.args.append("-demangle");
|
|
|
|
if (ctx.comp.linker_rdynamic) {
|
|
try ctx.args.append("-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("-static");
|
|
} else {
|
|
try ctx.args.append("-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("-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("-macosx_version_min"),
|
|
DarwinPlatform.Kind.IPhoneOS => try ctx.args.append("-iphoneos_version_min"),
|
|
DarwinPlatform.Kind.IPhoneOSSimulator => try ctx.args.append("-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("-no_pie");
|
|
} else {
|
|
try ctx.args.append("-pie");
|
|
}
|
|
}
|
|
|
|
try ctx.args.append("-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("-headerpad_max_install_names");
|
|
} else if (ctx.comp.is_static) {
|
|
try ctx.args.append("-lcrt0.o");
|
|
} else {
|
|
switch (platform.kind) {
|
|
DarwinPlatform.Kind.MacOS => {
|
|
if (platform.versionLessThan(10, 5)) {
|
|
try ctx.args.append("-lcrt1.o");
|
|
} else if (platform.versionLessThan(10, 6)) {
|
|
try ctx.args.append("-lcrt1.10.5.o");
|
|
} else if (platform.versionLessThan(10, 8)) {
|
|
try ctx.args.append("-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("-lcrt1.o");
|
|
} else if (platform.versionLessThan(6, 0)) {
|
|
try ctx.args.append("-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("-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("-undefined");
|
|
try ctx.args.append("dynamic_lookup");
|
|
}
|
|
|
|
if (platform.kind == DarwinPlatform.Kind.MacOS) {
|
|
if (platform.versionLessThan(10, 5)) {
|
|
try ctx.args.append("-lgcc_s.10.4");
|
|
} else if (platform.versionLessThan(10, 6)) {
|
|
try ctx.args.append("-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 {
|
|
@panic("TODO");
|
|
}
|
|
|
|
fn addFnObjects(ctx: *Context) !void {
|
|
// at this point it's guaranteed nobody else has this lock, so we circumvent it
|
|
// and avoid having to be an async function
|
|
const fn_link_set = &ctx.comp.fn_link_set.private_data;
|
|
|
|
var it = fn_link_set.first;
|
|
while (it) |node| {
|
|
const fn_val = node.data orelse {
|
|
// handle the tombstone. See Value.Fn.destroy.
|
|
it = node.next;
|
|
fn_link_set.remove(node);
|
|
ctx.comp.gpa().destroy(node);
|
|
continue;
|
|
};
|
|
try ctx.args.append(fn_val.containing_object.ptr());
|
|
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() == .macosx);
|
|
result.kind = Kind.MacOS;
|
|
break :blk "10.14";
|
|
},
|
|
};
|
|
|
|
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;
|
|
}
|