first pass at linking on macos
This commit is contained in:
269
src/link.cpp
269
src/link.cpp
@@ -50,6 +50,9 @@ static Buf *build_o(CodeGen *parent_gen, const char *oname) {
|
||||
codegen_set_verbose(child_gen, parent_gen->verbose);
|
||||
codegen_set_errmsg_color(child_gen, parent_gen->err_color);
|
||||
|
||||
codegen_set_mmacosx_version_min(child_gen, parent_gen->mmacosx_version_min);
|
||||
codegen_set_mios_version_min(child_gen, parent_gen->mios_version_min);
|
||||
|
||||
Buf *full_path = buf_alloc();
|
||||
os_path_join(std_dir_path, source_basename, full_path);
|
||||
Buf source_code = BUF_INIT;
|
||||
@@ -391,38 +394,251 @@ static void construct_linker_job_mingw(LinkJob *lj) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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).
|
||||
static bool darwin_get_release_version(const char *str, int *major, int *minor, int *micro, bool *had_extra) {
|
||||
*had_extra = false;
|
||||
|
||||
*major = 0;
|
||||
*minor = 0;
|
||||
*micro = 0;
|
||||
|
||||
if (*str == '\0')
|
||||
return false;
|
||||
|
||||
char *end;
|
||||
*major = strtol(str, &end, 10);
|
||||
if (*str != '\0' && *end == '\0')
|
||||
return true;
|
||||
if (*end != '.')
|
||||
return false;
|
||||
|
||||
str = end + 1;
|
||||
*minor = strtol(str, &end, 10);
|
||||
if (*str != '\0' && *end == '\0')
|
||||
return true;
|
||||
if (*end != '.')
|
||||
return false;
|
||||
|
||||
str = end + 1;
|
||||
*micro = strtol(str, &end, 10);
|
||||
if (*str != '\0' && *end == '\0')
|
||||
return true;
|
||||
if (str == end)
|
||||
return false;
|
||||
*had_extra = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
enum DarwinPlatformKind {
|
||||
MacOS,
|
||||
IPhoneOS,
|
||||
IPhoneOSSimulator,
|
||||
};
|
||||
|
||||
struct DarwinPlatform {
|
||||
DarwinPlatformKind kind;
|
||||
int major;
|
||||
int minor;
|
||||
int micro;
|
||||
};
|
||||
|
||||
static void get_darwin_platform(LinkJob *lj, DarwinPlatform *platform) {
|
||||
CodeGen *g = lj->codegen;
|
||||
|
||||
if (g->mmacosx_version_min) {
|
||||
platform->kind = MacOS;
|
||||
} else if (g->mios_version_min) {
|
||||
platform->kind = IPhoneOS;
|
||||
} else {
|
||||
zig_panic("unable to infer -macosx-version-min or -mios-version-min");
|
||||
}
|
||||
|
||||
bool had_extra;
|
||||
if (platform->kind == MacOS) {
|
||||
if (!darwin_get_release_version(buf_ptr(g->mmacosx_version_min),
|
||||
&platform->major, &platform->minor, &platform->micro, &had_extra) ||
|
||||
had_extra || platform->major != 10 || platform->minor >= 100 || platform->micro >= 100)
|
||||
{
|
||||
zig_panic("invalid -mmacosx-version-min");
|
||||
}
|
||||
} else if (platform->kind == IPhoneOS) {
|
||||
if (!darwin_get_release_version(buf_ptr(g->mios_version_min),
|
||||
&platform->major, &platform->minor, &platform->micro, &had_extra) ||
|
||||
had_extra || platform->major >= 10 || platform->minor >= 100 || platform->micro >= 100)
|
||||
{
|
||||
zig_panic("invalid -mios-version-min");
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
if (platform->kind == IPhoneOS &&
|
||||
(g->zig_target.arch.arch == ZigLLVM_x86 ||
|
||||
g->zig_target.arch.arch == ZigLLVM_x86_64))
|
||||
{
|
||||
platform->kind = IPhoneOSSimulator;
|
||||
}
|
||||
}
|
||||
|
||||
static bool darwin_version_lt(DarwinPlatform *platform, int major, int minor) {
|
||||
if (platform->major < major) {
|
||||
return true;
|
||||
} else if (platform->major > major) {
|
||||
return false;
|
||||
}
|
||||
if (platform->minor < minor) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void construct_linker_job_darwin(LinkJob *lj) {
|
||||
CodeGen *g = lj->codegen;
|
||||
|
||||
int ver_major;
|
||||
int ver_minor;
|
||||
int ver_micro;
|
||||
bool had_extra;
|
||||
|
||||
if (!darwin_get_release_version(buf_ptr(g->darwin_linker_version), &ver_major, &ver_minor, &ver_micro,
|
||||
&had_extra) || had_extra)
|
||||
{
|
||||
zig_panic("invalid linker version number");
|
||||
}
|
||||
|
||||
// Newer linkers support -demangle. Pass it if supported and not disabled by
|
||||
// the user.
|
||||
if (ver_major >= 100) {
|
||||
lj->args.append("-demangle");
|
||||
}
|
||||
|
||||
if (g->linker_rdynamic && ver_major >= 137) {
|
||||
lj->args.append("-export_dynamic");
|
||||
}
|
||||
|
||||
bool is_lib = g->out_type == OutTypeLib;
|
||||
bool shared = !g->is_static && is_lib;
|
||||
if (g->is_static) {
|
||||
lj->args.append("-static");
|
||||
} else {
|
||||
lj->args.append("-dynamic");
|
||||
}
|
||||
|
||||
if (is_lib) {
|
||||
zig_panic("TODO linker args on darwin for making a library");
|
||||
}
|
||||
|
||||
DarwinPlatform platform;
|
||||
get_darwin_platform(lj, &platform);
|
||||
switch (platform.kind) {
|
||||
case MacOS:
|
||||
lj->args.append("-macosx_version_min");
|
||||
break;
|
||||
case IPhoneOS:
|
||||
lj->args.append("-iphoneos_version_min");
|
||||
break;
|
||||
case IPhoneOSSimulator:
|
||||
lj->args.append("-ios_simulator_version_min");
|
||||
break;
|
||||
}
|
||||
lj->args.append(buf_ptr(buf_sprintf("%d.%d.%d", platform.major, platform.minor, platform.micro)));
|
||||
|
||||
|
||||
if (g->out_type == OutTypeExe) {
|
||||
if (g->is_static) {
|
||||
lj->args.append("-no_pie");
|
||||
} else {
|
||||
lj->args.append("-pie");
|
||||
}
|
||||
}
|
||||
|
||||
lj->args.append("-o");
|
||||
lj->args.append(buf_ptr(&lj->out_file));
|
||||
|
||||
if (lj->link_in_crt) {
|
||||
if (shared) {
|
||||
zig_panic("TODO");
|
||||
} else if (g->is_static) {
|
||||
lj->args.append("-lcrt0.o");
|
||||
} else {
|
||||
switch (platform.kind) {
|
||||
case MacOS:
|
||||
if (darwin_version_lt(&platform, 10, 5)) {
|
||||
lj->args.append("-lcrt1.o");
|
||||
} else if (darwin_version_lt(&platform, 10, 6)) {
|
||||
lj->args.append("-lcrt1.10.5.o");
|
||||
} else if (darwin_version_lt(&platform, 10, 8)) {
|
||||
lj->args.append("-lcrt1.10.6.o");
|
||||
}
|
||||
break;
|
||||
case IPhoneOS:
|
||||
if (g->zig_target.arch.arch == ZigLLVM_aarch64) {
|
||||
// iOS does not need any crt1 files for arm64
|
||||
} else if (darwin_version_lt(&platform, 3, 1)) {
|
||||
lj->args.append("-lcrt1.o");
|
||||
} else if (darwin_version_lt(&platform, 6, 0)) {
|
||||
lj->args.append("-lcrt1.3.1.o");
|
||||
}
|
||||
break;
|
||||
case IPhoneOSSimulator:
|
||||
// no crt1.o needed
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int 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);
|
||||
}
|
||||
|
||||
lj->args.append((const char *)buf_ptr(&lj->out_file_o));
|
||||
|
||||
for (int i = 0; i < g->link_libs.length; i += 1) {
|
||||
Buf *link_lib = g->link_libs.at(i);
|
||||
Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib));
|
||||
lj->args.append(buf_ptr(arg));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void construct_linker_job(LinkJob *lj) {
|
||||
switch (lj->codegen->zig_target.os) {
|
||||
case ZigLLVM_UnknownOS:
|
||||
zig_unreachable();
|
||||
zig_unreachable();
|
||||
case ZigLLVM_Linux:
|
||||
if (lj->codegen->zig_target.arch.arch == ZigLLVM_hexagon) {
|
||||
if (lj->codegen->zig_target.arch.arch == ZigLLVM_hexagon) {
|
||||
zig_panic("TODO construct hexagon_TC linker job");
|
||||
} else {
|
||||
} else {
|
||||
return construct_linker_job_linux(lj);
|
||||
}
|
||||
}
|
||||
case ZigLLVM_CloudABI:
|
||||
zig_panic("TODO construct CloudABI linker job");
|
||||
zig_panic("TODO construct CloudABI linker job");
|
||||
case ZigLLVM_Darwin:
|
||||
case ZigLLVM_MacOSX:
|
||||
case ZigLLVM_IOS:
|
||||
zig_panic("TODO construct DarwinClang linker job");
|
||||
return construct_linker_job_darwin(lj);
|
||||
case ZigLLVM_DragonFly:
|
||||
zig_panic("TODO construct DragonFly linker job");
|
||||
zig_panic("TODO construct DragonFly linker job");
|
||||
case ZigLLVM_OpenBSD:
|
||||
zig_panic("TODO construct OpenBSD linker job");
|
||||
zig_panic("TODO construct OpenBSD linker job");
|
||||
case ZigLLVM_Bitrig:
|
||||
zig_panic("TODO construct Bitrig linker job");
|
||||
zig_panic("TODO construct Bitrig linker job");
|
||||
case ZigLLVM_NetBSD:
|
||||
zig_panic("TODO construct NetBSD linker job");
|
||||
zig_panic("TODO construct NetBSD linker job");
|
||||
case ZigLLVM_FreeBSD:
|
||||
zig_panic("TODO construct FreeBSD linker job");
|
||||
zig_panic("TODO construct FreeBSD linker job");
|
||||
case ZigLLVM_Minix:
|
||||
zig_panic("TODO construct Minix linker job");
|
||||
zig_panic("TODO construct Minix linker job");
|
||||
case ZigLLVM_NaCl:
|
||||
zig_panic("TODO construct NaCl_TC linker job");
|
||||
zig_panic("TODO construct NaCl_TC linker job");
|
||||
case ZigLLVM_Solaris:
|
||||
zig_panic("TODO construct Solaris linker job");
|
||||
zig_panic("TODO construct Solaris linker job");
|
||||
case ZigLLVM_Win32:
|
||||
switch (lj->codegen->zig_target.environ) {
|
||||
default:
|
||||
@@ -440,27 +656,27 @@ static void construct_linker_job(LinkJob *lj) {
|
||||
case ZigLLVM_MSVC:
|
||||
case ZigLLVM_UnknownEnvironment:
|
||||
zig_panic("TODO construct MSVC linker job");
|
||||
}
|
||||
}
|
||||
case ZigLLVM_CUDA:
|
||||
zig_panic("TODO construct Cuda linker job");
|
||||
zig_panic("TODO construct Cuda linker job");
|
||||
default:
|
||||
// Of these targets, Hexagon is the only one that might have
|
||||
// an OS of Linux, in which case it got handled above already.
|
||||
if (lj->codegen->zig_target.arch.arch == ZigLLVM_tce) {
|
||||
// Of these targets, Hexagon is the only one that might have
|
||||
// an OS of Linux, in which case it got handled above already.
|
||||
if (lj->codegen->zig_target.arch.arch == ZigLLVM_tce) {
|
||||
zig_panic("TODO construct TCE linker job");
|
||||
} else if (lj->codegen->zig_target.arch.arch == ZigLLVM_hexagon) {
|
||||
} else if (lj->codegen->zig_target.arch.arch == ZigLLVM_hexagon) {
|
||||
zig_panic("TODO construct Hexagon_TC linker job");
|
||||
} else if (lj->codegen->zig_target.arch.arch == ZigLLVM_xcore) {
|
||||
} else if (lj->codegen->zig_target.arch.arch == ZigLLVM_xcore) {
|
||||
zig_panic("TODO construct XCore linker job");
|
||||
} else if (lj->codegen->zig_target.arch.arch == ZigLLVM_shave) {
|
||||
} else if (lj->codegen->zig_target.arch.arch == ZigLLVM_shave) {
|
||||
zig_panic("TODO construct SHAVE linker job");
|
||||
} else if (lj->codegen->zig_target.oformat == ZigLLVM_ELF) {
|
||||
} else if (lj->codegen->zig_target.oformat == ZigLLVM_ELF) {
|
||||
zig_panic("TODO construct Generic_ELF linker job");
|
||||
} else if (lj->codegen->zig_target.oformat == ZigLLVM_MachO) {
|
||||
} else if (lj->codegen->zig_target.oformat == ZigLLVM_MachO) {
|
||||
zig_panic("TODO construct MachO linker job");
|
||||
} else {
|
||||
} else {
|
||||
zig_panic("TODO construct Generic_GCC linker job");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -535,7 +751,6 @@ void codegen_link(CodeGen *g, const char *out_file) {
|
||||
}
|
||||
|
||||
lj.link_in_crt = (g->link_libc && g->out_type == OutTypeExe);
|
||||
// invoke `ld`
|
||||
ensure_we_have_linker_path(g);
|
||||
|
||||
construct_linker_job(&lj);
|
||||
|
||||
Reference in New Issue
Block a user