Commit 02886a8b93

Andrew Kelley <andrew@ziglang.org>
2020-09-23 20:01:15
stage2: support rpaths
1 parent c0b774f
src/link/Elf.zig
@@ -1272,6 +1272,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
     ch.hash.add(self.base.options.rdynamic);
     ch.hash.addListOfBytes(self.base.options.extra_lld_args);
     ch.hash.addListOfBytes(self.base.options.lib_dirs);
+    ch.hash.addListOfBytes(self.base.options.rpath_list);
+    ch.hash.add(self.base.options.each_lib_rpath);
     ch.hash.add(self.base.options.is_compiler_rt_or_libc);
     ch.hash.add(self.base.options.z_nodelete);
     ch.hash.add(self.base.options.z_defs);
@@ -1392,7 +1394,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
     }
 
     const full_out_path = if (directory.path) |dir_path|
-        try std.fs.path.join(arena, &[_][]const u8{dir_path, self.base.options.sub_path})
+        try fs.path.join(arena, &[_][]const u8{dir_path, self.base.options.sub_path})
     else 
         self.base.options.sub_path;
     try argv.append("-o");
@@ -1420,32 +1422,34 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
         }
     }
 
-    // TODO rpaths
-    // TODO add to cache hash above too
-    //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;
-    //            }
-    //        }
-    //    }
-    //}
+    // rpaths
+    var rpath_table = std.StringHashMap(void).init(self.base.allocator);
+    defer rpath_table.deinit();
+    for (self.base.options.rpath_list) |rpath| {
+        if ((try rpath_table.fetchPut(rpath, {})) == null) {
+            try argv.append("-rpath");
+            try argv.append(rpath);
+        }
+    }
+    if (self.base.options.each_lib_rpath) {
+        var test_path = std.ArrayList(u8).init(self.base.allocator);
+        defer test_path.deinit();
+        for (self.base.options.lib_dirs) |lib_dir_path| {
+            for (self.base.options.system_libs) |link_lib| {
+                test_path.shrinkRetainingCapacity(0);
+                const sep = fs.path.sep_str;
+                try test_path.writer().print("{}" ++ sep ++ "lib{}.so", .{ lib_dir_path, link_lib });
+                fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
+                    error.FileNotFound => continue,
+                    else => |e| return e,
+                };
+                if ((try rpath_table.fetchPut(lib_dir_path, {})) == null) {
+                    try argv.append("-rpath");
+                    try argv.append(lib_dir_path);
+                }
+            }
+        }
+    }
 
     for (self.base.options.lib_dirs) |lib_dir| {
         try argv.append("-L");
src/Compilation.zig
@@ -316,6 +316,7 @@ pub const InitOptions = struct {
     function_sections: ?bool = null,
     linker_allow_shlib_undefined: ?bool = null,
     linker_bind_global_refs_locally: ?bool = null,
+    each_lib_rpath: ?bool = null,
     disable_c_depfile: bool = false,
     linker_z_nodelete: bool = false,
     linker_z_defs: bool = false,
@@ -714,6 +715,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
             .error_return_tracing = error_return_tracing,
             .llvm_cpu_features = llvm_cpu_features,
             .is_compiler_rt_or_libc = options.is_compiler_rt_or_libc,
+            .each_lib_rpath = options.each_lib_rpath orelse false,
         });
         errdefer bin_file.destroy();
         comp.* = .{
src/link.zig
@@ -65,6 +65,7 @@ pub const Options = struct {
     dll_export_fns: bool,
     error_return_tracing: bool,
     is_compiler_rt_or_libc: bool,
+    each_lib_rpath: bool,
     gc_sections: ?bool = null,
     allow_shlib_undefined: ?bool = null,
     linker_script: ?[]const u8 = null,
src/main.zig
@@ -251,6 +251,7 @@ const usage_build_generic =
     \\  -L[d], --library-directory [d] Add a directory to the library search path
     \\  -T[script]                     Use a custom linker script
     \\  --dynamic-linker [path]        Set the dynamic interpreter path (usually ld.so)
+    \\  --each-lib-rpath               Add rpath for each used dynamic library
     \\  --version [ver]                Dynamic library semver
     \\  -rdynamic                      Add all symbols to the dynamic symbol table
     \\  -rpath [path]                  Add directory to the runtime library search path
@@ -361,6 +362,7 @@ pub fn buildOutputType(
     var use_lld: ?bool = null;
     var use_clang: ?bool = null;
     var link_eh_frame_hdr = false;
+    var each_lib_rpath = false;
     var libc_paths_file: ?[]const u8 = null;
     var machine_code_model: std.builtin.CodeModel = .default;
     var runtime_args_start: ?usize = null;
@@ -613,6 +615,8 @@ pub fn buildOutputType(
                         if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
                         i += 1;
                         override_lib_dir = args[i];
+                    } else if (mem.eql(u8, arg, "--each-lib-rpath")) {
+                        each_lib_rpath = true;
                     } else if (mem.eql(u8, arg, "--enable-cache")) {
                         enable_cache = true;
                     } else if (mem.eql(u8, arg, "--test-cmd-bin")) {
@@ -1421,6 +1425,7 @@ pub fn buildOutputType(
         .color = color,
         .time_report = time_report,
         .is_test = arg_mode == .zig_test,
+        .each_lib_rpath = each_lib_rpath,
         .test_evented_io = test_evented_io,
         .test_filter = test_filter,
         .test_name_prefix = test_name_prefix,
BRANCH_TODO
@@ -1,4 +1,3 @@
- * support rpaths in ELF linker code
  * musl
  * implement proper parsing of LLD stderr/stdout and exposing compile errors
  * tests passing with -Dskip-non-native