dynamic linker path is independent from libc installation

This commit is contained in:
Andrew Kelley 2019-03-05 15:54:08 -05:00
parent 0d10ab0680
commit 55a0016221
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
9 changed files with 90 additions and 66 deletions

View File

@ -1851,6 +1851,7 @@ struct CodeGen {
ZigPackage *root_package;
Buf *zig_lib_dir;
Buf *zig_std_dir;
Buf *dynamic_linker_path;
const char **llvm_argv;
size_t llvm_argv_len;

View File

@ -257,6 +257,10 @@ void codegen_set_out_name(CodeGen *g, Buf *out_name) {
g->root_out_name = out_name;
}
void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker_path) {
g->dynamic_linker_path = dynamic_linker_path;
}
void codegen_add_lib_dir(CodeGen *g, const char *dir) {
g->lib_dirs.append(dir);
}
@ -7908,6 +7912,51 @@ static void init(CodeGen *g) {
}
}
static void detect_dynamic_linker(CodeGen *g) {
if (g->dynamic_linker_path != nullptr)
return;
if (g->zig_target->is_native) {
// target_dynamic_linker is usually correct. However on some systems, such as NixOS
// it will be incorrect. See if we can do better by looking at what zig's own
// dynamic linker path is.
g->dynamic_linker_path = get_self_dynamic_linker_path();
if (g->dynamic_linker_path != nullptr)
return;
// If Zig is statically linked, such as via distributed binary static builds, the above
// trick won't work. What are we left with? Try to run the system C compiler and get
// it to tell us the dynamic linker path
#if defined(ZIG_OS_LINUX)
{
Error err;
static const char *dyn_tests[] = {
#if defined(ZIG_ARCH_X86_64)
"ld-linux-x86-64.so.2",
"ld-musl-x86_64.so.1",
#endif
};
Buf *result = buf_alloc();
for (size_t i = 0; i < array_length(dyn_tests); i += 1) {
const char *lib_name = dyn_tests[i];
if ((err = zig_libc_cc_print_file_name(lib_name, result, false, true))) {
if (err != ErrorCCompilerCannotFindFile) {
fprintf(stderr, "Unable to detect native dynamic linker: %s\n", err_str(err));
exit(1);
}
continue;
}
g->dynamic_linker_path = result;
return;
}
}
#endif
}
// Otherwise go with the standard linker path.
g->dynamic_linker_path = buf_create_from_str(target_dynamic_linker(g->zig_target));
}
static void detect_libc(CodeGen *g) {
Error err;
@ -9029,8 +9078,8 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
cache_buf(ch, &g->libc->crt_dir);
cache_buf(ch, &g->libc->msvc_lib_dir);
cache_buf(ch, &g->libc->kernel32_lib_dir);
cache_buf(ch, &g->libc->dynamic_linker_path);
}
cache_buf(ch, g->dynamic_linker_path);
gen_c_objects(g);
@ -9132,6 +9181,7 @@ void codegen_build_and_link(CodeGen *g) {
assert(g->out_type != OutTypeUnknown);
detect_libc(g);
detect_dynamic_linker(g);
Buf *artifact_dir = buf_alloc();
Buf digest = BUF_INIT;

View File

@ -29,6 +29,7 @@ void codegen_set_is_static(CodeGen *codegen, bool is_static);
void codegen_set_strip(CodeGen *codegen, bool strip);
void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color);
void codegen_set_out_name(CodeGen *codegen, Buf *out_name);
void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker);
void codegen_add_lib_dir(CodeGen *codegen, const char *dir);
void codegen_add_forbidden_lib(CodeGen *codegen, Buf *lib);
LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib);

View File

@ -1,4 +1,5 @@
#include "cache_hash.hpp"
#include "os.hpp"
#include <stdio.h>
@ -8,8 +9,9 @@ static Buf saved_stage1_path = BUF_INIT;
static Buf saved_lib_dir = BUF_INIT;
static Buf saved_special_dir = BUF_INIT;
static Buf saved_std_dir = BUF_INIT;
static Buf saved_dynamic_linker_path = BUF_INIT;
Buf *get_stage1_cache_path() {
Buf *get_stage1_cache_path(void) {
if (saved_stage1_path.list.length != 0) {
return &saved_stage1_path;
}
@ -57,6 +59,13 @@ Error get_compiler_id(Buf **result) {
Buf *lib_path = lib_paths.at(i);
if ((err = cache_add_file(ch, lib_path)))
return err;
#if defined(ZIG_OS_LINUX) && defined(ZIG_ARCH_X86_64)
if (buf_ends_with_str(lib_path, "ld-linux-x86-64.so.2")) {
buf_init_from_buf(&saved_dynamic_linker_path, lib_path);
} else if (buf_ends_with_str(lib_path, "ld-musl-x86-64.so.1")) {
buf_init_from_buf(&saved_dynamic_linker_path, lib_path);
}
#endif
}
if ((err = cache_final(ch, &saved_compiler_id)))
return err;
@ -67,6 +76,11 @@ Error get_compiler_id(Buf **result) {
return ErrorNone;
}
Buf *get_self_dynamic_linker_path(void) {
Buf *dontcare;
(void)get_compiler_id(&dontcare); // for the side-effects of caching the dynamic linker path
return (saved_dynamic_linker_path.list.length == 0) ? nullptr : &saved_dynamic_linker_path;
}
static bool test_zig_install_prefix(Buf *test_path, Buf *out_zig_lib_dir) {
Buf lib_buf = BUF_INIT;

View File

@ -11,11 +11,12 @@
#include "buffer.hpp"
#include "error.hpp"
Buf *get_stage1_cache_path();
Buf *get_stage1_cache_path(void);
Error get_compiler_id(Buf **result);
Buf *get_self_dynamic_linker_path(void);
Buf *get_zig_lib_dir();
Buf *get_zig_special_dir();
Buf *get_zig_std_dir();
Buf *get_zig_lib_dir(void);
Buf *get_zig_special_dir(void);
Buf *get_zig_std_dir(void);
#endif

View File

@ -16,7 +16,6 @@ static const char *zig_libc_keys[] = {
"crt_dir",
"msvc_lib_dir",
"kernel32_lib_dir",
"dynamic_linker_path",
};
static const size_t zig_libc_keys_len = array_length(zig_libc_keys);
@ -37,7 +36,6 @@ static void zig_libc_init_empty(ZigLibCInstallation *libc) {
buf_init_from_str(&libc->crt_dir, "");
buf_init_from_str(&libc->msvc_lib_dir, "");
buf_init_from_str(&libc->kernel32_lib_dir, "");
buf_init_from_str(&libc->dynamic_linker_path, "");
}
Error zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file, const ZigTarget *target, bool verbose) {
@ -78,7 +76,6 @@ Error zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file, const ZigTarget
match = match || zig_libc_match_key(name, value, found_keys, 2, &libc->crt_dir);
match = match || zig_libc_match_key(name, value, found_keys, 3, &libc->msvc_lib_dir);
match = match || zig_libc_match_key(name, value, found_keys, 4, &libc->kernel32_lib_dir);
match = match || zig_libc_match_key(name, value, found_keys, 5, &libc->dynamic_linker_path);
}
for (size_t i = 0; i < zig_libc_keys_len; i += 1) {
@ -131,15 +128,6 @@ Error zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file, const ZigTarget
}
}
if (buf_len(&libc->dynamic_linker_path) == 0) {
if (!target_is_darwin(target) && target->os != OsWindows) {
if (verbose) {
fprintf(stderr, "dynamic_linker_path may not be empty for %s\n", target_os_name(target->os));
}
return ErrorSemanticAnalyzeFail;
}
}
return ErrorNone;
}
@ -301,8 +289,8 @@ static Error zig_libc_find_native_include_dir_posix(ZigLibCInstallation *self, b
}
return ErrorFileNotFound;
}
#if !defined(ZIG_OS_DARWIN) && !defined(ZIG_OS_FREEBSD) && !defined(ZIG_OS_NETBSD)
static Error zig_libc_cc_print_file_name(const char *o_file, Buf *out, bool want_dirname, bool verbose) {
#if defined(ZIG_OS_LINUX)
Error zig_libc_cc_print_file_name(const char *o_file, Buf *out, bool want_dirname, bool verbose) {
const char *cc_exe = getenv("CC");
cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
ZigList<const char *> args = {};
@ -340,32 +328,6 @@ static Error zig_libc_find_native_crt_dir_posix(ZigLibCInstallation *self, bool
return zig_libc_cc_print_file_name("crt1.o", &self->crt_dir, true, verbose);
}
#endif
static Error zig_libc_find_native_dynamic_linker_posix(ZigLibCInstallation *self, bool verbose) {
#if defined(ZIG_OS_LINUX)
Error err;
static const char *dyn_tests[] = {
"ld-linux-x86-64.so.2",
"ld-musl-x86_64.so.1",
};
for (size_t i = 0; i < array_length(dyn_tests); i += 1) {
const char *lib_name = dyn_tests[i];
if ((err = zig_libc_cc_print_file_name(lib_name, &self->dynamic_linker_path, false, true))) {
if (err != ErrorCCompilerCannotFindFile)
return err;
continue;
}
return ErrorNone;
}
#endif
ZigTarget native_target;
get_native_target(&native_target);
const char *dynamic_linker_path = target_dynamic_linker(&native_target);
if (dynamic_linker_path != nullptr) {
buf_init_from_str(&self->dynamic_linker_path, dynamic_linker_path);
}
return ErrorNone;
}
#endif
void zig_libc_render(ZigLibCInstallation *self, FILE *file) {
@ -391,17 +353,12 @@ void zig_libc_render(ZigLibCInstallation *self, FILE *file) {
"# Only needed when targeting Windows.\n"
"kernel32_lib_dir=%s\n"
"\n"
"# The full path to the dynamic linker, on the target system.\n"
"# Not needed when targeting MacOS or Windows.\n"
"dynamic_linker_path=%s\n"
"\n"
,
buf_ptr(&self->include_dir),
buf_ptr(&self->sys_include_dir),
buf_ptr(&self->crt_dir),
buf_ptr(&self->msvc_lib_dir),
buf_ptr(&self->kernel32_lib_dir),
buf_ptr(&self->dynamic_linker_path)
buf_ptr(&self->kernel32_lib_dir)
);
}
@ -438,12 +395,10 @@ Error zig_libc_find_native(ZigLibCInstallation *self, bool verbose) {
return err;
#if defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
buf_init_from_str(&self->crt_dir, "/usr/lib");
#elif !defined(ZIG_OS_DARWIN)
#elif defined(ZIG_OS_LINUX)
if ((err = zig_libc_find_native_crt_dir_posix(self, verbose)))
return err;
#endif
if ((err = zig_libc_find_native_dynamic_linker_posix(self, verbose)))
return err;
return ErrorNone;
#endif
}

View File

@ -21,7 +21,6 @@ struct ZigLibCInstallation {
Buf crt_dir;
Buf msvc_lib_dir;
Buf kernel32_lib_dir;
Buf dynamic_linker_path;
};
Error ATTRIBUTE_MUST_USE zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file,
@ -30,4 +29,8 @@ void zig_libc_render(ZigLibCInstallation *self, FILE *file);
Error ATTRIBUTE_MUST_USE zig_libc_find_native(ZigLibCInstallation *self, bool verbose);
#if defined(ZIG_OS_LINUX)
Error zig_libc_cc_print_file_name(const char *o_file, Buf *out, bool want_dirname, bool verbose);
#endif
#endif

View File

@ -517,14 +517,9 @@ static void construct_linker_job_elf(LinkJob *lj) {
}
if (!g->is_static) {
if (g->libc != nullptr) {
assert(buf_len(&g->libc->dynamic_linker_path) != 0);
lj->args.append("-dynamic-linker");
lj->args.append(buf_ptr(&g->libc->dynamic_linker_path));
} else {
lj->args.append("-dynamic-linker");
lj->args.append(target_dynamic_linker(g->zig_target));
}
assert(g->dynamic_linker_path != nullptr);
lj->args.append("-dynamic-linker");
lj->args.append(buf_ptr(g->dynamic_linker_path));
}
}
@ -545,7 +540,6 @@ static void construct_linker_job_elf(LinkJob *lj) {
lj->args.append(buf_ptr(builtin_a_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));
}

View File

@ -166,7 +166,7 @@ static int print_target_list(FILE *f) {
SubArchList sub_arch_list = target_subarch_list(arch);
size_t sub_count = target_subarch_count(sub_arch_list);
const char *arch_native_str = (native.arch == arch) ? " (native)" : "";
fprintf(stderr, " %s%s\n", arch_name, arch_native_str);
fprintf(f, " %s%s\n", arch_name, arch_native_str);
for (size_t sub_i = 0; sub_i < sub_count; sub_i += 1) {
ZigLLVM_SubArchType sub = target_subarch_enum(sub_arch_list, sub_i);
const char *sub_name = target_subarch_name(sub);
@ -406,6 +406,7 @@ int main(int argc, char **argv) {
bool verbose_cc = false;
ErrColor color = ErrColorAuto;
CacheOpt enable_cache = CacheOptAuto;
const char *dynamic_linker = nullptr;
const char *libc_txt = nullptr;
ZigList<const char *> clang_argv = {0};
ZigList<const char *> llvm_argv = {0};
@ -715,6 +716,8 @@ int main(int argc, char **argv) {
}
} else if (strcmp(arg, "--name") == 0) {
out_name = argv[i];
} else if (strcmp(arg, "--dynamic-linker") == 0) {
dynamic_linker = argv[i];
} else if (strcmp(arg, "--libc") == 0) {
libc_txt = argv[i];
} else if (strcmp(arg, "-isystem") == 0) {
@ -1027,6 +1030,8 @@ int main(int argc, char **argv) {
codegen_set_llvm_argv(g, llvm_argv.items, llvm_argv.length);
codegen_set_strip(g, strip);
codegen_set_is_static(g, is_static);
if (dynamic_linker != nullptr)
codegen_set_dynamic_linker(g, buf_create_from_str(dynamic_linker));
g->verbose_tokenize = verbose_tokenize;
g->verbose_ast = verbose_ast;
g->verbose_link = verbose_link;