2011-10-04 17:23:32 -05:00
|
|
|
import std::os;
|
|
|
|
import std::fs;
|
2011-10-04 22:07:18 -05:00
|
|
|
import std::os_fs;
|
2011-10-04 17:23:32 -05:00
|
|
|
import std::vec;
|
2011-10-04 22:07:18 -05:00
|
|
|
import std::map;
|
|
|
|
import std::str;
|
|
|
|
import std::uint;
|
2011-10-04 17:23:32 -05:00
|
|
|
import metadata::cstore;
|
|
|
|
import driver::session;
|
|
|
|
import util::filesearch;
|
|
|
|
|
2011-10-05 14:08:08 -05:00
|
|
|
// FIXME #721: Despite the compiler warning, test does exist and needs
|
|
|
|
// to be exported
|
2011-10-04 17:23:32 -05:00
|
|
|
export get_rpath_flags, test;
|
|
|
|
|
2011-10-05 00:40:38 -05:00
|
|
|
fn get_rpath_flags(sess: session::session, out_filename: str) -> [str] {
|
2011-10-06 15:11:56 -05:00
|
|
|
// No rpath on windows
|
|
|
|
if sess.get_targ_cfg().os == session::os_win32 {
|
|
|
|
ret [];
|
|
|
|
}
|
|
|
|
|
2011-10-04 17:23:32 -05:00
|
|
|
log "preparing the RPATH!";
|
|
|
|
|
|
|
|
let cwd = os::getcwd();
|
|
|
|
let sysroot = sess.filesearch().sysroot();
|
|
|
|
let output = out_filename;
|
|
|
|
let libs = cstore::get_used_crate_files(sess.get_cstore());
|
2011-10-05 01:12:46 -05:00
|
|
|
// We don't currently rpath native libraries, but we know
|
|
|
|
// where rustrt is and we know every rust program needs it
|
|
|
|
let libs = libs + [get_sysroot_absolute_rt_lib(sess)];
|
|
|
|
|
2011-10-04 17:23:32 -05:00
|
|
|
let target_triple = sess.get_opts().target_triple;
|
|
|
|
let rpaths = get_rpaths(cwd, sysroot, output, libs, target_triple);
|
2011-10-05 01:36:06 -05:00
|
|
|
rpaths_to_flags(rpaths)
|
2011-10-04 17:23:32 -05:00
|
|
|
}
|
|
|
|
|
2011-10-05 01:12:46 -05:00
|
|
|
fn get_sysroot_absolute_rt_lib(sess: session::session) -> fs::path {
|
|
|
|
let path = [sess.filesearch().sysroot()]
|
|
|
|
+ filesearch::relative_target_lib_path(
|
|
|
|
sess.get_opts().target_triple)
|
|
|
|
+ [os::dylib_filename("rustrt")];
|
|
|
|
check vec::is_not_empty(path);
|
|
|
|
fs::connect_many(path)
|
|
|
|
}
|
|
|
|
|
2011-10-04 17:23:32 -05:00
|
|
|
fn rpaths_to_flags(rpaths: [str]) -> [str] {
|
|
|
|
vec::map({ |rpath| #fmt("-Wl,-rpath,%s",rpath)}, rpaths)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_rpaths(cwd: fs::path, sysroot: fs::path,
|
|
|
|
output: fs::path, libs: [fs::path],
|
|
|
|
target_triple: str) -> [str] {
|
|
|
|
log #fmt("cwd: %s", cwd);
|
|
|
|
log #fmt("sysroot: %s", sysroot);
|
|
|
|
log #fmt("output: %s", output);
|
|
|
|
log #fmt("libs:");
|
|
|
|
for libpath in libs {
|
|
|
|
log #fmt(" %s", libpath);
|
|
|
|
}
|
|
|
|
log #fmt("target_triple: %s", target_triple);
|
|
|
|
|
|
|
|
// Use relative paths to the libraries. Binaries can be moved
|
|
|
|
// as long as they maintain the relative relationship to the
|
|
|
|
// crates they depend on.
|
2011-10-05 00:40:38 -05:00
|
|
|
let rel_rpaths = get_rpaths_relative_to_output(cwd, output, libs);
|
2011-10-04 17:23:32 -05:00
|
|
|
|
|
|
|
// Make backup absolute paths to the libraries. Binaries can
|
|
|
|
// be moved as long as the crates they link against don't move.
|
2011-10-05 00:40:38 -05:00
|
|
|
let abs_rpaths = get_absolute_rpaths(cwd, libs);
|
2011-10-04 17:23:32 -05:00
|
|
|
|
|
|
|
// And a final backup rpath to the global library location.
|
2011-10-05 00:40:38 -05:00
|
|
|
let fallback_rpaths = [get_install_prefix_rpath(target_triple)];
|
|
|
|
|
|
|
|
fn log_rpaths(desc: str, rpaths: [str]) {
|
|
|
|
log #fmt("%s rpaths:", desc);
|
|
|
|
for rpath in rpaths {
|
|
|
|
log #fmt(" %s", rpath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
log_rpaths("relative", rel_rpaths);
|
|
|
|
log_rpaths("absolute", abs_rpaths);
|
|
|
|
log_rpaths("fallback", fallback_rpaths);
|
|
|
|
|
|
|
|
let rpaths = rel_rpaths + abs_rpaths + fallback_rpaths;
|
2011-10-04 17:23:32 -05:00
|
|
|
|
|
|
|
// Remove duplicates
|
|
|
|
let rpaths = minimize_rpaths(rpaths);
|
|
|
|
ret rpaths;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_rpaths_relative_to_output(cwd: fs::path,
|
|
|
|
output: fs::path,
|
|
|
|
libs: [fs::path]) -> [str] {
|
|
|
|
vec::map(bind get_rpath_relative_to_output(cwd, output, _), libs)
|
|
|
|
}
|
|
|
|
|
2011-10-04 22:07:18 -05:00
|
|
|
fn get_rpath_relative_to_output(cwd: fs::path,
|
|
|
|
output: fs::path,
|
|
|
|
lib: fs::path) -> str {
|
|
|
|
"$ORIGIN" + fs::path_sep() + get_relative_to(
|
2011-10-04 17:23:32 -05:00
|
|
|
get_absolute(cwd, output),
|
2011-10-04 22:07:18 -05:00
|
|
|
get_absolute(cwd, lib))
|
2011-10-04 17:23:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Find the relative path from one file to another
|
2011-10-04 22:07:18 -05:00
|
|
|
fn get_relative_to(abs1: fs::path, abs2: fs::path) -> fs::path {
|
|
|
|
assert fs::path_is_absolute(abs1);
|
|
|
|
assert fs::path_is_absolute(abs2);
|
2011-10-05 00:40:38 -05:00
|
|
|
log #fmt("finding relative path from %s to %s",
|
|
|
|
abs1, abs2);
|
2011-10-04 22:07:18 -05:00
|
|
|
let normal1 = fs::normalize(abs1);
|
|
|
|
let normal2 = fs::normalize(abs2);
|
|
|
|
let split1 = str::split(normal1, os_fs::path_sep as u8);
|
|
|
|
let split2 = str::split(normal2, os_fs::path_sep as u8);
|
|
|
|
let len1 = vec::len(split1);
|
|
|
|
let len2 = vec::len(split2);
|
|
|
|
assert len1 > 0u;
|
|
|
|
assert len2 > 0u;
|
|
|
|
|
|
|
|
let max_common_path = uint::min(len1, len2) - 1u;
|
|
|
|
let start_idx = 0u;
|
|
|
|
while start_idx < max_common_path
|
|
|
|
&& split1[start_idx] == split2[start_idx] {
|
|
|
|
start_idx += 1u;
|
|
|
|
}
|
|
|
|
|
|
|
|
let path = [];
|
|
|
|
|
|
|
|
for each _ in uint::range(start_idx, len1 - 1u) {
|
|
|
|
path += [".."];
|
|
|
|
}
|
|
|
|
|
|
|
|
path += vec::slice(split2, start_idx, len2 - 1u);
|
|
|
|
|
2011-10-05 00:40:38 -05:00
|
|
|
if check vec::is_not_empty(path) {
|
|
|
|
ret fs::connect_many(path);
|
|
|
|
} else {
|
|
|
|
ret ".";
|
|
|
|
}
|
2011-10-04 17:23:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_absolute_rpaths(cwd: fs::path, libs: [fs::path]) -> [str] {
|
|
|
|
vec::map(bind get_absolute_rpath(cwd, _), libs)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_absolute_rpath(cwd: fs::path, lib: fs::path) -> str {
|
2011-10-05 00:40:38 -05:00
|
|
|
fs::dirname(get_absolute(cwd, lib))
|
2011-10-04 17:23:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_absolute(cwd: fs::path, lib: fs::path) -> fs::path {
|
|
|
|
if fs::path_is_absolute(lib) {
|
|
|
|
lib
|
|
|
|
} else {
|
|
|
|
fs::connect(cwd, lib)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_install_prefix_rpath(target_triple: str) -> str {
|
|
|
|
let install_prefix = #env("CFG_PREFIX");
|
|
|
|
|
|
|
|
if install_prefix == "" {
|
|
|
|
fail "rustc compiled without CFG_PREFIX environment variable";
|
|
|
|
}
|
|
|
|
|
|
|
|
let path = [install_prefix]
|
|
|
|
+ filesearch::relative_target_lib_path(target_triple);
|
|
|
|
check vec::is_not_empty(path);
|
|
|
|
fs::connect_many(path)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn minimize_rpaths(rpaths: [str]) -> [str] {
|
|
|
|
let set = map::new_str_hash::<()>();
|
|
|
|
let minimized = [];
|
2011-10-05 00:40:38 -05:00
|
|
|
for rpath in rpaths {
|
|
|
|
if !set.contains_key(rpath) {
|
|
|
|
minimized += [rpath];
|
|
|
|
set.insert(rpath, ());
|
|
|
|
}
|
|
|
|
}
|
2011-10-04 17:23:32 -05:00
|
|
|
ret minimized;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
#[cfg(target_os = "macos")]
|
2011-10-06 15:29:36 -05:00
|
|
|
#[cfg(test)]
|
2011-10-04 17:23:32 -05:00
|
|
|
mod test {
|
|
|
|
#[test]
|
|
|
|
fn test_rpaths_to_flags() {
|
|
|
|
let flags = rpaths_to_flags(["path1", "path2"]);
|
|
|
|
assert flags == ["-Wl,-rpath,path1", "-Wl,-rpath,path2"];
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_get_absolute1() {
|
|
|
|
let cwd = "/dir";
|
|
|
|
let lib = "some/path/lib";
|
|
|
|
let res = get_absolute(cwd, lib);
|
|
|
|
assert res == "/dir/some/path/lib";
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_get_absolute2() {
|
|
|
|
let cwd = "/dir";
|
|
|
|
let lib = "/some/path/lib";
|
|
|
|
let res = get_absolute(cwd, lib);
|
|
|
|
assert res == "/some/path/lib";
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_prefix_rpath() {
|
|
|
|
let res = get_install_prefix_rpath("triple");
|
|
|
|
assert res == #env("CFG_PREFIX") + "/lib/rustc/triple/lib";
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2011-10-05 00:40:38 -05:00
|
|
|
fn test_minimize1() {
|
2011-10-04 17:23:32 -05:00
|
|
|
let res = minimize_rpaths(["rpath1", "rpath2", "rpath1"]);
|
|
|
|
assert res == ["rpath1", "rpath2"];
|
|
|
|
}
|
|
|
|
|
2011-10-05 00:40:38 -05:00
|
|
|
#[test]
|
|
|
|
fn test_minimize2() {
|
|
|
|
let res = minimize_rpaths(["1a", "2", "2", "1a", "4a",
|
|
|
|
"1a", "2", "3", "4a", "3"]);
|
|
|
|
assert res == ["1a", "2", "4a", "3"];
|
|
|
|
}
|
|
|
|
|
2011-10-04 17:23:32 -05:00
|
|
|
#[test]
|
|
|
|
fn test_relative_to1() {
|
|
|
|
let p1 = "/usr/bin/rustc";
|
|
|
|
let p2 = "/usr/lib/mylib";
|
|
|
|
let res = get_relative_to(p1, p2);
|
|
|
|
assert res == "../lib";
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_relative_to2() {
|
|
|
|
let p1 = "/usr/bin/rustc";
|
|
|
|
let p2 = "/usr/bin/../lib/mylib";
|
|
|
|
let res = get_relative_to(p1, p2);
|
|
|
|
assert res == "../lib";
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_relative_to3() {
|
|
|
|
let p1 = "/usr/bin/whatever/rustc";
|
|
|
|
let p2 = "/usr/lib/whatever/mylib";
|
|
|
|
let res = get_relative_to(p1, p2);
|
|
|
|
assert res == "../../lib/whatever";
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_relative_to4() {
|
|
|
|
let p1 = "/usr/bin/whatever/../rustc";
|
|
|
|
let p2 = "/usr/lib/whatever/mylib";
|
|
|
|
let res = get_relative_to(p1, p2);
|
|
|
|
assert res == "../lib/whatever";
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_relative_to5() {
|
|
|
|
let p1 = "/usr/bin/whatever/../rustc";
|
|
|
|
let p2 = "/usr/lib/whatever/../mylib";
|
|
|
|
let res = get_relative_to(p1, p2);
|
2011-10-04 22:07:18 -05:00
|
|
|
assert res == "../lib";
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_relative_to6() {
|
|
|
|
let p1 = "/1";
|
|
|
|
let p2 = "/2/3";
|
|
|
|
let res = get_relative_to(p1, p2);
|
|
|
|
assert res == "2";
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_relative_to7() {
|
|
|
|
let p1 = "/1/2";
|
|
|
|
let p2 = "/3";
|
|
|
|
let res = get_relative_to(p1, p2);
|
|
|
|
assert res == "..";
|
|
|
|
}
|
|
|
|
|
2011-10-05 00:40:38 -05:00
|
|
|
#[test]
|
|
|
|
fn test_relative_to8() {
|
|
|
|
let p1 = "/home/brian/Dev/rust/build/"
|
|
|
|
+ "stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so";
|
|
|
|
let p2 = "/home/brian/Dev/rust/build/stage2/bin/.."
|
|
|
|
+ "/lib/rustc/i686-unknown-linux-gnu/lib/libstd.so";
|
|
|
|
let res = get_relative_to(p1, p2);
|
|
|
|
assert res == ".";
|
|
|
|
}
|
|
|
|
|
2011-10-04 22:07:18 -05:00
|
|
|
#[test]
|
|
|
|
fn test_rpath_relative() {
|
|
|
|
let res = get_rpath_relative_to_output(
|
|
|
|
"/usr", "bin/rustc", "lib/libstd.so");
|
|
|
|
assert res == "$ORIGIN/../lib";
|
2011-10-04 17:23:32 -05:00
|
|
|
}
|
2011-10-05 00:40:38 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_get_absolute_rpath() {
|
|
|
|
let res = get_absolute_rpath("/usr", "lib/libstd.so");
|
|
|
|
assert res == "/usr/lib";
|
|
|
|
}
|
2011-10-04 17:23:32 -05:00
|
|
|
}
|