From eb6856c307ae8cff97c57f11be2cf04561e7f2eb Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 15 May 2014 19:28:46 +0200 Subject: [PATCH] Fixing rustdoc stage1. See #13983 and #14000. Fix was originally authored by alexcrichton and then rebased a couple times by pnkfelix, most recently atop PR 13954. ---- Regarding the change to librustdoc/lib.rs, to do `map_err` before unwrapping a `TqskResult`: I do not understand how master is passing without this change or something like it, since `Box` does not implement `Show`. (Is this something that is only a problem for the snapshot stage0 compiler?) Still, the change I have put in here (which was added as part of a rebase after alex's review) seems harmless to me to apply to rustdoc at all stages, since a call to `unwrap` is just going to `fail!` on the err case anyway. --- src/compiletest/procsrv.rs | 63 +++++++++----------------- src/librustc/metadata/filesearch.rs | 2 +- src/librustdoc/lib.rs | 2 +- src/librustdoc/test.rs | 28 +++++++++++- src/libstd/unstable/dynamic_lib.rs | 68 +++++++++++++++++++++-------- 5 files changed, 100 insertions(+), 63 deletions(-) diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs index 9f62fd7096c..6b273c2d463 100644 --- a/src/compiletest/procsrv.rs +++ b/src/compiletest/procsrv.rs @@ -11,54 +11,31 @@ use std::os; use std::str; use std::io::process::{ProcessExit, Command, Process, ProcessOutput}; +use std::unstable::dynamic_lib::DynamicLibrary; -#[cfg(target_os = "win32")] fn target_env(lib_path: &str, prog: &str) -> Vec<(StrBuf, StrBuf)> { - let env = os::env(); - - // Make sure we include the aux directory in the path - assert!(prog.ends_with(".exe")); - let aux_path = prog.slice(0u, prog.len() - 4u).to_owned() + ".libaux"; - - let mut new_env: Vec<_> = env.move_iter().map(|(k, v)| { - let new_v = if "PATH" == k { - format_strbuf!("{};{};{}", v, lib_path, aux_path) - } else { - v.to_strbuf() - }; - (k.to_strbuf(), new_v) - }).collect(); - if prog.ends_with("rustc.exe") { - new_env.push(("RUST_THREADS".to_strbuf(), "1".to_strbuf())); - } - return new_env; -} - -#[cfg(target_os = "linux")] -#[cfg(target_os = "macos")] -#[cfg(target_os = "freebsd")] -fn target_env(lib_path: &str, prog: &str) -> Vec<(StrBuf,StrBuf)> { - // Make sure we include the aux directory in the path + let prog = if cfg!(windows) {prog.slice_to(prog.len() - 4)} else {prog}; let aux_path = prog + ".libaux"; + // Need to be sure to put both the lib_path and the aux path in the dylib + // search path for the child. + let mut path = DynamicLibrary::search_path(); + path.insert(0, Path::new(aux_path)); + path.insert(0, Path::new(lib_path)); + + // Remove the previous dylib search path var + let var = DynamicLibrary::envvar(); let mut env: Vec<(StrBuf,StrBuf)> = - os::env().move_iter() - .map(|(ref k, ref v)| (k.to_strbuf(), v.to_strbuf())) - .collect(); - let var = if cfg!(target_os = "macos") { - "DYLD_LIBRARY_PATH" - } else { - "LD_LIBRARY_PATH" - }; - let prev = match env.iter().position(|&(ref k, _)| k.as_slice() == var) { - Some(i) => env.remove(i).unwrap().val1(), - None => "".to_strbuf(), - }; - env.push((var.to_strbuf(), if prev.is_empty() { - format_strbuf!("{}:{}", lib_path, aux_path) - } else { - format_strbuf!("{}:{}:{}", lib_path, aux_path, prev) - })); + os::env().move_iter().map(|(a,b)|(a.to_strbuf(), b.to_strbuf())).collect(); + match env.iter().position(|&(ref k, _)| k.as_slice() == var) { + Some(i) => { env.remove(i); } + None => {} + } + + // Add the new dylib search path var + let newpath = DynamicLibrary::create_path(path.as_slice()); + env.push((var.to_strbuf(), + str::from_utf8(newpath.as_slice()).unwrap().to_strbuf())); return env; } diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index f339c6c8f74..238b23d6c5a 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -136,7 +136,7 @@ impl<'a> FileSearch<'a> { pub fn add_dylib_search_paths(&self) { self.for_each_lib_search_path(|lib_search_path| { - DynamicLibrary::add_search_path(lib_search_path); + DynamicLibrary::prepend_search_path(lib_search_path); FileDoesntMatch }) } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 2a7808fdf77..48db910fc39 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -284,7 +284,7 @@ fn rust_input(cratefile: &str, matches: &getopts::Matches) -> Output { core::run_core(libs.move_iter().map(|x| x.clone()).collect(), cfgs.move_iter().map(|x| x.to_strbuf()).collect(), &cr) - }).unwrap(); + }).map_err(|boxed_any|format!("{:?}", boxed_any)).unwrap(); info!("finished with rustc"); analysiskey.replace(Some(analysis)); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index c56841a076d..6a07b7a906e 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -15,6 +15,7 @@ use std::io::{Command, TempDir}; use std::os; use std::str; use std::strbuf::StrBuf; +use std::unstable::dynamic_lib::DynamicLibrary; use collections::{HashSet, HashMap}; use testing; @@ -150,12 +151,37 @@ fn runtest(test: &str, cratename: &str, libs: HashSet, should_fail: bool, let outdir = TempDir::new("rustdoctest").expect("rustdoc needs a tempdir"); let out = Some(outdir.path().clone()); let cfg = config::build_configuration(&sess); + let libdir = sess.target_filesearch().get_lib_path(); driver::compile_input(sess, cfg, &input, &out, &None); if no_run { return } // Run the code! - match Command::new(outdir.path().join("rust_out")).output() { + // + // We're careful to prepend the *target* dylib search path to the child's + // environment to ensure that the target loads the right libraries at + // runtime. It would be a sad day if the *host* libraries were loaded as a + // mistake. + let exe = outdir.path().join("rust_out"); + let env = { + let mut path = DynamicLibrary::search_path(); + path.insert(0, libdir.clone()); + + // Remove the previous dylib search path var + let var = DynamicLibrary::envvar(); + let mut env: Vec<(~str,~str)> = os::env().move_iter().collect(); + match env.iter().position(|&(ref k, _)| k.as_slice() == var) { + Some(i) => { env.remove(i); } + None => {} + }; + + // Add the new dylib search path var + let newpath = DynamicLibrary::create_path(path.as_slice()); + env.push((var.to_owned(), + str::from_utf8(newpath.as_slice()).unwrap().to_owned())); + env + }; + match Command::new(exe).env(env.as_slice()).output() { Err(e) => fail!("couldn't run the test: {}{}", e, if e.kind == io::PermissionDenied { " - maybe your tempdir is mounted with noexec?" diff --git a/src/libstd/unstable/dynamic_lib.rs b/src/libstd/unstable/dynamic_lib.rs index 4a9c5349459..d50c63c5832 100644 --- a/src/libstd/unstable/dynamic_lib.rs +++ b/src/libstd/unstable/dynamic_lib.rs @@ -16,16 +16,16 @@ A simple wrapper over the platform's dynamic library facilities */ - +use clone::Clone; use c_str::ToCStr; +use iter::Iterator; use mem; use ops::*; use option::*; use os; -use path::GenericPath; -use path; +use path::{Path,GenericPath}; use result::*; -use slice::Vector; +use slice::{Vector,ImmutableVector}; use str; use vec::Vec; @@ -76,22 +76,55 @@ impl DynamicLibrary { } } - /// Appends a path to the system search path for dynamic libraries - pub fn add_search_path(path: &path::Path) { - let (envvar, sep) = if cfg!(windows) { - ("PATH", ';' as u8) + /// Prepends a path to this process's search path for dynamic libraries + pub fn prepend_search_path(path: &Path) { + let mut search_path = DynamicLibrary::search_path(); + search_path.insert(0, path.clone()); + let newval = DynamicLibrary::create_path(search_path.as_slice()); + os::setenv(DynamicLibrary::envvar(), + str::from_utf8(newval.as_slice()).unwrap()); + } + + /// From a slice of paths, create a new vector which is suitable to be an + /// environment variable for this platforms dylib search path. + pub fn create_path(path: &[Path]) -> Vec { + let mut newvar = Vec::new(); + for (i, path) in path.iter().enumerate() { + if i > 0 { newvar.push(DynamicLibrary::separator()); } + newvar.push_all(path.as_vec()); + } + return newvar; + } + + /// Returns the environment variable for this process's dynamic library + /// search path + pub fn envvar() -> &'static str { + if cfg!(windows) { + "PATH" } else if cfg!(target_os = "macos") { - ("DYLD_LIBRARY_PATH", ':' as u8) + "DYLD_LIBRARY_PATH" } else { - ("LD_LIBRARY_PATH", ':' as u8) - }; - let mut newenv = Vec::from_slice(path.as_vec()); - newenv.push(sep); - match os::getenv_as_bytes(envvar) { - Some(bytes) => newenv.push_all(bytes), + "LD_LIBRARY_PATH" + } + } + + fn separator() -> u8 { + if cfg!(windows) {';' as u8} else {':' as u8} + } + + /// Returns the current search path for dynamic libraries being used by this + /// process + pub fn search_path() -> Vec { + let mut ret = Vec::new(); + match os::getenv_as_bytes(DynamicLibrary::envvar()) { + Some(env) => { + for portion in env.split(|a| *a == DynamicLibrary::separator()) { + ret.push(Path::new(portion)); + } + } None => {} } - os::setenv(envvar, str::from_utf8(newenv.as_slice()).unwrap()); + return ret; } /// Access the value at the symbol of the dynamic library @@ -168,11 +201,12 @@ mod test { #[cfg(target_os = "macos")] #[cfg(target_os = "freebsd")] pub mod dl { + use prelude::*; + use c_str::ToCStr; use libc; use ptr; use str; - use result::*; pub unsafe fn open_external(filename: T) -> *u8 { filename.with_c_str(|raw_name| {