add --each-lib-rpath option and corresponding config option

This adds an rpath entry for each used dynamic library directory.
This is necessary on some systems such as NixOS.
This commit is contained in:
Andrew Kelley 2017-03-13 13:11:55 -04:00
parent d10bbd28e9
commit 7efa2cd81c
9 changed files with 61 additions and 4 deletions

View File

@ -18,6 +18,7 @@ set(ZIG_LIBC_LIB_DIR "" CACHE STRING "Default native target libc directory where
set(ZIG_LIBC_STATIC_LIB_DIR "" CACHE STRING "Default native target libc directory where crtbeginT.o can be found")
set(ZIG_LIBC_INCLUDE_DIR "/usr/include" CACHE STRING "Default native target libc include directory")
set(ZIG_DYNAMIC_LINKER "" CACHE STRING "Override dynamic linker for native target")
set(ZIG_EACH_LIB_RPATH off CACHE BOOL "Add each dynamic library to rpath for native target")
option(ZIG_TEST_COVERAGE "Build Zig with test coverage instrumentation" OFF)

View File

@ -1413,6 +1413,7 @@ struct CodeGen {
uint32_t test_fn_count;
bool check_unused;
bool each_lib_rpath;
ZigList<AstNode *> error_decls;
bool generate_error_name_table;

View File

@ -90,6 +90,7 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {
g->libc_static_lib_dir = buf_create_from_str("");
g->libc_include_dir = buf_create_from_str("");
g->darwin_linker_version = buf_create_from_str("");
g->each_lib_rpath = false;
} else {
// native compilation, we can rely on the configuration stuff
g->is_native_target = true;
@ -100,6 +101,9 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {
g->libc_static_lib_dir = buf_create_from_str(ZIG_LIBC_STATIC_LIB_DIR);
g->libc_include_dir = buf_create_from_str(ZIG_LIBC_INCLUDE_DIR);
g->darwin_linker_version = buf_create_from_str(ZIG_HOST_LINK_VERSION);
#ifdef ZIG_EACH_LIB_RPATH
g->each_lib_rpath = true;
#endif
if (g->zig_target.os == ZigLLVM_Darwin ||
g->zig_target.os == ZigLLVM_MacOSX ||
@ -138,6 +142,10 @@ void codegen_set_check_unused(CodeGen *g, bool check_unused) {
g->check_unused = check_unused;
}
void codegen_set_each_lib_rpath(CodeGen *g, bool each_lib_rpath) {
g->each_lib_rpath = each_lib_rpath;
}
void codegen_set_errmsg_color(CodeGen *g, ErrColor err_color) {
g->err_color = err_color;
}

View File

@ -20,6 +20,7 @@ void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);
void codegen_set_is_release(CodeGen *codegen, bool is_release);
void codegen_set_is_test(CodeGen *codegen, bool is_test);
void codegen_set_check_unused(CodeGen *codegen, bool check_unused);
void codegen_set_each_lib_rpath(CodeGen *codegen, bool each_lib_rpath);
void codegen_set_is_static(CodeGen *codegen, bool is_static);
void codegen_set_strip(CodeGen *codegen, bool strip);

View File

@ -21,6 +21,7 @@
#define ZIG_DYNAMIC_LINKER "@ZIG_DYNAMIC_LINKER@"
#define ZIG_HOST_LINK_VERSION "@ZIG_HOST_LINK_VERSION@"
#cmakedefine ZIG_EACH_LIB_RPATH
#cmakedefine ZIG_LLVM_OLD_CXX_ABI
// Only used for running tests before installing.

View File

@ -17,6 +17,7 @@ struct LinkJob {
ZigList<const char *> args;
bool link_in_crt;
Buf out_file_o;
HashMap<Buf *, bool, buf_hash, buf_eql_buf> rpath_table;
};
static const char *get_libc_file(CodeGen *g, const char *file) {
@ -148,6 +149,16 @@ static const char *getLDMOption(const ZigTarget *t) {
}
}
static void add_rpath(LinkJob *lj, Buf *rpath) {
if (lj->rpath_table.maybe_get(rpath) != nullptr)
return;
lj->args.append("-rpath");
lj->args.append(buf_ptr(rpath));
lj->rpath_table.put(rpath, true);
}
static void construct_linker_job_elf(LinkJob *lj) {
CodeGen *g = lj->codegen;
@ -205,8 +216,24 @@ static void construct_linker_job_elf(LinkJob *lj) {
for (size_t i = 0; i < g->rpath_list.length; i += 1) {
Buf *rpath = g->rpath_list.at(i);
lj->args.append("-rpath");
lj->args.append(buf_ptr(rpath));
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.length; i += 1) {
Buf *link_lib = g->link_libs.at(i);
bool does_exist;
Buf *test_path = buf_sprintf("%s/lib%s.so", lib_dir, buf_ptr(link_lib));
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) {
@ -708,6 +735,7 @@ static void construct_linker_job(LinkJob *lj) {
void codegen_link(CodeGen *g, const char *out_file) {
LinkJob lj = {0};
lj.rpath_table.init(4);
lj.codegen = g;
if (out_file) {
buf_init_from_str(&lj.out_file, out_file);

View File

@ -58,7 +58,8 @@ static int usage(const char *arg0) {
" -framework [name] (darwin only) link against framework\n"
" --check-unused perform semantic analysis on unused declarations\n"
" --linker-script [path] use a custom linker script\n"
" -rpath [path] add a directory to the runtime library search path\n"
" -rpath [path] add directory to the runtime library search path\n"
" --each-lib-rpath add rpath for each used dynamic library\n"
, arg0);
return EXIT_FAILURE;
}
@ -143,6 +144,7 @@ int main(int argc, char **argv) {
bool check_unused = false;
const char *linker_script = nullptr;
ZigList<const char *> rpath_list = {0};
bool each_lib_rpath = false;
for (int i = 1; i < argc; i += 1) {
char *arg = argv[i];
@ -166,6 +168,8 @@ int main(int argc, char **argv) {
rdynamic = true;
} else if (strcmp(arg, "--check-unused") == 0) {
check_unused = true;
} else if (strcmp(arg, "--each-lib-rpath") == 0) {
each_lib_rpath = true;
} else if (arg[1] == 'L' && arg[2] != 0) {
// alias for --library-path
lib_dirs.append(&arg[2]);
@ -351,6 +355,8 @@ int main(int argc, char **argv) {
codegen_set_is_test(g, cmd == CmdTest);
codegen_set_linker_script(g, linker_script);
codegen_set_check_unused(g, check_unused);
if (each_lib_rpath)
codegen_set_each_lib_rpath(g, each_lib_rpath);
codegen_set_clang_argv(g, clang_argv.items, clang_argv.length);
codegen_set_strip(g, strip);

View File

@ -218,6 +218,15 @@ int os_fetch_file(FILE *f, Buf *out_buf) {
zig_unreachable();
}
int os_file_exists(Buf *full_path, bool *result) {
#if defined(ZIG_OS_POSIX)
*result = access(buf_ptr(full_path), F_OK) != -1;
return 0;
#else
zig_panic("TODO implement os_file_exists for non-posix");
#endif
}
#if defined(ZIG_OS_POSIX)
static int os_exec_process_posix(const char *exe, ZigList<const char *> &args,
Termination *term, Buf *out_stderr, Buf *out_stdout)

View File

@ -10,6 +10,7 @@
#include "list.hpp"
#include "buffer.hpp"
#include "error.hpp"
#include <stdio.h>
@ -40,7 +41,6 @@ bool os_path_is_absolute(Buf *path);
void os_write_file(Buf *full_path, Buf *contents);
int os_fetch_file(FILE *file, Buf *out_contents);
int os_fetch_file_path(Buf *full_path, Buf *out_contents);
@ -51,4 +51,6 @@ bool os_stderr_tty(void);
int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path);
int os_delete_file(Buf *path);
int os_file_exists(Buf *full_path, bool *result);
#endif