diff --git a/src/Cargo.lock b/src/Cargo.lock index e7bf1b6b4e1..d26098903ee 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1933,7 +1933,6 @@ dependencies = [ "rustc_privacy 0.0.0", "rustc_resolve 0.0.0", "rustc_save_analysis 0.0.0", - "rustc_trans 0.0.0", "rustc_trans_utils 0.0.0", "rustc_typeck 0.0.0", "serialize 0.0.0", @@ -1984,6 +1983,7 @@ dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "build_helper 0.1.0", "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", ] @@ -2121,6 +2121,7 @@ dependencies = [ "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "jobserver 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", diff --git a/src/Cargo.toml b/src/Cargo.toml index ad795b23cf2..c22ba7a37c8 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -4,6 +4,7 @@ members = [ "rustc", "libstd", "libtest", + "librustc_trans", "tools/cargotest", "tools/clippy", "tools/compiletest", diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 0bc82c4f9f2..e6871764b2c 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -94,7 +94,7 @@ impl Step for Rustc { build.clear_if_dirty(&stage_out, &libtest_stamp(build, compiler, target)); let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check"); - rustc_cargo(build, target, &mut cargo); + rustc_cargo(build, &mut cargo); run_cargo(build, &mut cargo, &librustc_stamp(build, compiler, target), diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 21bbd82dd33..0b247c6f755 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -300,7 +300,11 @@ impl Step for StartupObjects { } for obj in ["crt2.o", "dllcrt2.o"].iter() { - copy(&compiler_file(build.cc(target), obj), &sysroot_dir.join(obj)); + let src = compiler_file(build, + build.cc(target), + target, + obj); + copy(&src, &sysroot_dir.join(obj)); } } } @@ -454,10 +458,6 @@ impl Step for Rustc { builder.ensure(Test { compiler, target }); - // Build LLVM for our target. This will implicitly build the host LLVM - // if necessary. - builder.ensure(native::Llvm { target }); - if build.force_use_stage1(compiler, target) { builder.ensure(Rustc { compiler: builder.compiler(1, build.build), @@ -487,7 +487,7 @@ impl Step for Rustc { build.clear_if_dirty(&stage_out, &libtest_stamp(build, compiler, target)); let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build"); - rustc_cargo(build, target, &mut cargo); + rustc_cargo(build, &mut cargo); run_cargo(build, &mut cargo, &librustc_stamp(build, compiler, target), @@ -501,14 +501,14 @@ impl Step for Rustc { } } -/// Same as `std_cargo`, but for libtest -pub fn rustc_cargo(build: &Build, - target: Interned, - cargo: &mut Command) { +pub fn rustc_cargo(build: &Build, cargo: &mut Command) { cargo.arg("--features").arg(build.rustc_features()) .arg("--manifest-path") .arg(build.src.join("src/rustc/Cargo.toml")); + rustc_cargo_env(build, cargo); +} +fn rustc_cargo_env(build: &Build, cargo: &mut Command) { // Set some configuration variables picked up by build scripts and // the compiler alike cargo.env("CFG_RELEASE", build.rust_release()) @@ -536,27 +536,6 @@ pub fn rustc_cargo(build: &Build, if !build.unstable_features() { cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1"); } - // Flag that rust llvm is in use - if build.is_rust_llvm(target) { - cargo.env("LLVM_RUSTLLVM", "1"); - } - cargo.env("LLVM_CONFIG", build.llvm_config(target)); - let target_config = build.config.target_config.get(&target); - if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { - cargo.env("CFG_LLVM_ROOT", s); - } - // Building with a static libstdc++ is only supported on linux right now, - // not for MSVC or macOS - if build.config.llvm_static_stdcpp && - !target.contains("freebsd") && - !target.contains("windows") && - !target.contains("apple") { - cargo.env("LLVM_STATIC_STDCPP", - compiler_file(build.cxx(target).unwrap(), "libstdc++.a")); - } - if build.config.llvm_link_shared { - cargo.env("LLVM_LINK_SHARED", "1"); - } if let Some(ref s) = build.config.rustc_default_linker { cargo.env("CFG_DEFAULT_LINKER", s); } @@ -601,6 +580,137 @@ impl Step for RustcLink { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct RustcTrans { + pub compiler: Compiler, + pub target: Interned, +} + +impl Step for RustcTrans { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/librustc_trans").krate("rustc_trans") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(RustcTrans { + compiler: run.builder.compiler(run.builder.top_stage, run.host), + target: run.target, + }); + } + + fn run(self, builder: &Builder) { + let build = builder.build; + let compiler = self.compiler; + let target = self.target; + + builder.ensure(Rustc { compiler, target }); + + // Build LLVM for our target. This will implicitly build the host LLVM + // if necessary. + builder.ensure(native::Llvm { target }); + + if build.force_use_stage1(compiler, target) { + builder.ensure(RustcTrans { + compiler: builder.compiler(1, build.build), + target, + }); + return; + } + + let _folder = build.fold_output(|| format!("stage{}-rustc_trans", compiler.stage)); + println!("Building stage{} trans artifacts ({} -> {})", + compiler.stage, &compiler.host, target); + + let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build"); + cargo.arg("--manifest-path") + .arg(build.src.join("src/librustc_trans/Cargo.toml")) + .arg("--features").arg(build.rustc_features()); + rustc_cargo_env(build, &mut cargo); + + // Pass down configuration from the LLVM build into the build of + // librustc_llvm and librustc_trans. + if build.is_rust_llvm(target) { + cargo.env("LLVM_RUSTLLVM", "1"); + } + cargo.env("LLVM_CONFIG", build.llvm_config(target)); + let target_config = build.config.target_config.get(&target); + if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { + cargo.env("CFG_LLVM_ROOT", s); + } + // Building with a static libstdc++ is only supported on linux right now, + // not for MSVC or macOS + if build.config.llvm_static_stdcpp && + !target.contains("freebsd") && + !target.contains("windows") && + !target.contains("apple") { + let file = compiler_file(build, + build.cxx(target).unwrap(), + target, + "libstdc++.a"); + cargo.env("LLVM_STATIC_STDCPP", file); + } + if build.config.llvm_link_shared { + cargo.env("LLVM_LINK_SHARED", "1"); + } + + run_cargo(build, + &mut cargo, + &librustc_trans_stamp(build, compiler, target), + false); + } +} + +/// Creates the `codegen-backends` folder for a compiler that's about to be +/// assembled as a complete compiler. +/// +/// This will take the codegen artifacts produced by `compiler` and link them +/// into an appropriate location for `target_compiler` to be a functional +/// compiler. +fn copy_codegen_backends_to_sysroot(builder: &Builder, + compiler: Compiler, + target_compiler: Compiler) { + let build = builder.build; + let target = target_compiler.host; + + // Note that this step is different than all the other `*Link` steps in + // that it's not assembling a bunch of libraries but rather is primarily + // moving the codegen backend into place. The codegen backend of rustc is + // not linked into the main compiler by default but is rather dynamically + // selected at runtime for inclusion. + // + // Here we're looking for the output dylib of the `RustcTrans` step and + // we're copying that into the `codegen-backends` folder. + let libdir = builder.sysroot_libdir(target_compiler, target); + let dst = libdir.join("codegen-backends"); + t!(fs::create_dir_all(&dst)); + let stamp = librustc_trans_stamp(build, compiler, target); + + let mut copied = None; + for file in read_stamp_file(&stamp) { + let filename = match file.file_name().and_then(|s| s.to_str()) { + Some(s) => s, + None => continue, + }; + if !is_dylib(filename) || !filename.contains("rustc_trans-") { + continue + } + match copied { + None => copied = Some(file.clone()), + Some(ref s) => { + panic!("copied two codegen backends:\n{}\n{}", + s.display(), + file.display()); + } + } + copy(&file, &dst.join(filename)); + } + assert!(copied.is_some(), "failed to find a codegen backend to copy"); +} + /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. pub fn libstd_stamp(build: &Build, compiler: Compiler, target: Interned) -> PathBuf { @@ -619,9 +729,20 @@ pub fn librustc_stamp(build: &Build, compiler: Compiler, target: Interned PathBuf { - let out = output(Command::new(compiler) - .arg(format!("-print-file-name={}", file))); +pub fn librustc_trans_stamp(build: &Build, + compiler: Compiler, + target: Interned) -> PathBuf { + build.cargo_out(compiler, Mode::Librustc, target).join(".librustc_trans.stamp") +} + +fn compiler_file(build: &Build, + compiler: &Path, + target: Interned, + file: &str) -> PathBuf { + let mut cmd = Command::new(compiler); + cmd.args(build.cflags(target)); + cmd.arg(format!("-print-file-name={}", file)); + let out = output(&mut cmd); PathBuf::from(out.trim()) } @@ -690,20 +811,23 @@ impl Step for Assemble { } // Get the compiler that we'll use to bootstrap ourselves. - let build_compiler = if target_compiler.host != build.build { - // Build a compiler for the host platform. We cannot use the stage0 - // compiler for the host platform for this because it doesn't have - // the libraries we need. FIXME: Perhaps we should download those - // libraries? It would make builds faster... - // FIXME: It may be faster if we build just a stage 1 - // compiler and then use that to bootstrap this compiler - // forward. - builder.compiler(target_compiler.stage - 1, build.build) - } else { - // Build the compiler we'll use to build the stage requested. This - // may build more than one compiler (going down to stage 0). - builder.compiler(target_compiler.stage - 1, target_compiler.host) - }; + // + // Note that this is where the recursive nature of the bootstrap + // happens, as this will request the previous stage's compiler on + // downwards to stage 0. + // + // Also note that we're building a compiler for the host platform. We + // only assume that we can run `build` artifacts, which means that to + // produce some other architecture compiler we need to start from + // `build` to get there. + // + // FIXME: Perhaps we should download those libraries? + // It would make builds faster... + // + // FIXME: It may be faster if we build just a stage 1 compiler and then + // use that to bootstrap this compiler forward. + let build_compiler = + builder.compiler(target_compiler.stage - 1, build.build); // Build the libraries for this compiler to link to (i.e., the libraries // it uses at runtime). NOTE: Crates the target compiler compiles don't @@ -721,7 +845,14 @@ impl Step for Assemble { builder.ensure(RustcLink { compiler, target_compiler, target }); } } else { - builder.ensure(Rustc { compiler: build_compiler, target: target_compiler.host }); + builder.ensure(Rustc { + compiler: build_compiler, + target: target_compiler.host, + }); + builder.ensure(RustcTrans { + compiler: build_compiler, + target: target_compiler.host, + }); } let stage = target_compiler.stage; @@ -740,9 +871,12 @@ impl Step for Assemble { } } - let out_dir = build.cargo_out(build_compiler, Mode::Librustc, host); + copy_codegen_backends_to_sysroot(builder, + build_compiler, + target_compiler); // Link the compiler binary itself into place + let out_dir = build.cargo_out(build_compiler, Mode::Librustc, host); let rustc = out_dir.join(exe("rustc", &*host)); let bindir = sysroot.join("bin"); t!(fs::create_dir_all(&bindir)); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 224b31ef268..4127239dc49 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -434,6 +434,15 @@ impl Step for Rustc { } } + // Copy over the codegen backends + let backends_src = builder.sysroot_libdir(compiler, host) + .join("codegen-backends"); + let backends_dst = image.join("lib/rustlib") + .join(&*host) + .join("lib/codegen-backends"); + t!(fs::create_dir_all(&backends_dst)); + cp_r(&backends_src, &backends_dst); + // Man pages t!(fs::create_dir_all(image.join("share/man/man1"))); let man_src = build.src.join("src/doc/man"); @@ -581,7 +590,9 @@ impl Step for Std { t!(fs::create_dir_all(&dst)); let mut src = builder.sysroot_libdir(compiler, target).to_path_buf(); src.pop(); // Remove the trailing /lib folder from the sysroot_libdir - cp_r(&src, &dst); + cp_filtered(&src, &dst, &|path| { + path.file_name().and_then(|s| s.to_str()) != Some("codegen-backends") + }); let mut cmd = rust_installer(builder); cmd.arg("generate") diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 9bf762a3b4b..6a75fc5112f 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -617,7 +617,7 @@ impl Step for Rustc { t!(symlink_dir_force(&my_out, &out_dir)); let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc"); - compile::rustc_cargo(build, target, &mut cargo); + compile::rustc_cargo(build, &mut cargo); if build.config.compiler_docs { // src/rustc/Cargo.toml contains a bin crate called rustc which diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index a6a5ba67723..8928bef9faa 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -432,9 +432,6 @@ impl Build { if self.config.use_jemalloc { features.push_str(" jemalloc"); } - if self.config.llvm_enabled { - features.push_str(" llvm"); - } features } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index ba8cf3a8e2e..442098a7afa 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -57,11 +57,6 @@ impl Step for Llvm { let build = builder.build; let target = self.target; - // If we're not compiling for LLVM bail out here. - if !build.config.llvm_enabled { - return; - } - // If we're using a custom LLVM bail out here, but we can only use a // custom LLVM for the build triple. if let Some(config) = build.config.target_config.get(&target) { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 5faec279438..a316b0f7ef9 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -900,6 +900,8 @@ impl Step for Compiletest { cmd.env("PROFILER_SUPPORT", "1"); } + cmd.env("RUST_TEST_TMPDIR", build.out.join("tmp")); + cmd.arg("--adb-path").arg("adb"); cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR); if target.contains("android") { @@ -1209,7 +1211,7 @@ impl Step for Crate { } Mode::Librustc => { builder.ensure(compile::Rustc { compiler, target }); - compile::rustc_cargo(build, target, &mut cargo); + compile::rustc_cargo(build, &mut cargo); ("librustc", "rustc-main") } _ => panic!("can only test libraries"), diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index f95dbcf411c..2c4898cb2c0 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -14,7 +14,7 @@ bitflags = "1.0" fmt_macros = { path = "../libfmt_macros" } graphviz = { path = "../libgraphviz" } jobserver = "0.1" -log = "0.4" +log = { version = "0.4", features = ["release_max_level_info", "std"] } rustc_apfloat = { path = "../librustc_apfloat" } rustc_back = { path = "../librustc_back" } rustc_const_math = { path = "../librustc_const_math" } @@ -26,7 +26,6 @@ syntax_pos = { path = "../libsyntax_pos" } backtrace = "0.3.3" byteorder = { version = "1.1", features = ["i128"]} - # Note that these dependencies are a lie, they're just here to get linkage to # work. # diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index 4f7bbd79275..18493b8bb39 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } graphviz = { path = "../libgraphviz" } -log = { version = "0.4", features = ["release_max_level_info"] } +log = "0.4" env_logger = { version = "0.4", default-features = false } rustc = { path = "../librustc" } rustc_allocator = { path = "../librustc_allocator" } @@ -29,7 +29,6 @@ rustc_plugin = { path = "../librustc_plugin" } rustc_privacy = { path = "../librustc_privacy" } rustc_resolve = { path = "../librustc_resolve" } rustc_save_analysis = { path = "../librustc_save_analysis" } -rustc_trans = { path = "../librustc_trans", optional = true } rustc_trans_utils = { path = "../librustc_trans_utils" } rustc_typeck = { path = "../librustc_typeck" } serialize = { path = "../libserialize" } @@ -38,6 +37,3 @@ syntax_ext = { path = "../libsyntax_ext" } syntax_pos = { path = "../libsyntax_pos" } ar = "0.3.0" - -[features] -llvm = ["rustc_trans"] diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index cdb50a0ae48..029cceda532 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -47,8 +47,6 @@ extern crate rustc_metadata; extern crate rustc_mir; extern crate rustc_resolve; extern crate rustc_save_analysis; -#[cfg(feature="llvm")] -pub extern crate rustc_trans; extern crate rustc_trans_utils; extern crate rustc_typeck; extern crate serialize; @@ -68,30 +66,36 @@ use rustc::session::{self, config, Session, build_session, CompileResult}; use rustc::session::CompileIncomplete; use rustc::session::config::{Input, PrintRequest, ErrorOutputType}; use rustc::session::config::nightly_options; +use rustc::session::filesearch; use rustc::session::{early_error, early_warn}; use rustc::lint::Lint; use rustc::lint; use rustc::middle::cstore::CrateStore; use rustc_metadata::locator; use rustc_metadata::cstore::CStore; +use rustc_metadata::dynamic_lib::DynamicLibrary; use rustc::util::common::{time, ErrorReported}; use rustc_trans_utils::trans_crate::TransCrate; use serialize::json::ToJson; use std::any::Any; -use std::cmp::max; use std::cmp::Ordering::Equal; +use std::cmp::max; use std::default::Default; +use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::env; use std::ffi::OsString; use std::io::{self, Read, Write}; use std::iter::repeat; +use std::mem; use std::panic; -use std::path::PathBuf; +use std::path::{PathBuf, Path}; use std::process::{self, Command, Stdio}; use std::rc::Rc; use std::str; +use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; +use std::sync::{Once, ONCE_INIT}; use std::thread; use syntax::ast; @@ -176,57 +180,247 @@ pub fn run(run_compiler: F) -> isize 0 } -#[cfg(not(feature="llvm"))] -pub use rustc_trans_utils::trans_crate::MetadataOnlyTransCrate as DefaultTransCrate; -#[cfg(feature="llvm")] -pub use rustc_trans::LlvmTransCrate as DefaultTransCrate; - -#[cfg(not(feature="llvm"))] -pub mod rustc_trans { - pub use rustc_trans_utils::trans_crate::MetadataOnlyTransCrate as LlvmTransCrate; - - pub fn print_version() {} - pub fn print_passes() {} -} - -fn load_backend_from_dylib(sess: &Session, backend_name: &str) -> Box { - use std::path::Path; - use rustc_metadata::dynamic_lib::DynamicLibrary; - - match DynamicLibrary::open(Some(Path::new(backend_name))) { - Ok(lib) => { - unsafe { - let trans = { - let __rustc_codegen_backend: unsafe fn(&Session) -> Box; - __rustc_codegen_backend = match lib.symbol("__rustc_codegen_backend") { - Ok(f) => ::std::mem::transmute::<*mut u8, _>(f), - Err(e) => sess.fatal(&format!("Couldnt load codegen backend as it\ - doesn't export the __rustc_backend_new symbol: {:?}", e)), - }; - __rustc_codegen_backend(sess) - }; - ::std::mem::forget(lib); - trans - } - } +fn load_backend_from_dylib(path: &Path) -> fn() -> Box { + // Note that we're specifically using `open_global_now` here rather than + // `open`, namely we want the behavior on Unix of RTLD_GLOBAL and RTLD_NOW, + // where NOW means "bind everything right now" because we don't want + // surprises later on and RTLD_GLOBAL allows the symbols to be made + // available for future dynamic libraries opened. This is currently used by + // loading LLVM and then making its symbols available for other dynamic + // libraries. + let lib = match DynamicLibrary::open_global_now(path) { + Ok(lib) => lib, Err(err) => { - sess.fatal(&format!("Couldnt load codegen backend {:?}: {:?}", backend_name, err)); + let err = format!("couldn't load codegen backend {:?}: {:?}", + path, + err); + early_error(ErrorOutputType::default(), &err); + } + }; + unsafe { + match lib.symbol("__rustc_codegen_backend") { + Ok(f) => { + mem::forget(lib); + mem::transmute::<*mut u8, _>(f) + } + Err(e) => { + let err = format!("couldn't load codegen backend as it \ + doesn't export the `__rustc_codegen_backend` \ + symbol: {:?}", e); + early_error(ErrorOutputType::default(), &err); + } } } } pub fn get_trans(sess: &Session) -> Box { - let trans_name = sess.opts.debugging_opts.codegen_backend.clone(); - match trans_name.as_ref().map(|s|&**s) { - None => DefaultTransCrate::new(&sess), - Some("llvm") => rustc_trans::LlvmTransCrate::new(&sess), - Some("metadata_only") => { - rustc_trans_utils::trans_crate::MetadataOnlyTransCrate::new(&sess) + static INIT: Once = ONCE_INIT; + static mut LOAD: fn() -> Box = || unreachable!(); + + INIT.call_once(|| { + let trans_name = sess.opts.debugging_opts.codegen_backend.as_ref(); + let backend = match trans_name.map(|s| &**s) { + None | + Some("llvm") => get_trans_default(), + Some("metadata_only") => { + rustc_trans_utils::trans_crate::MetadataOnlyTransCrate::new + } + Some(filename) if filename.contains(".") => { + load_backend_from_dylib(filename.as_ref()) + } + Some(trans_name) => { + sess.fatal(&format!("unknown codegen backend {}", trans_name)); + } + }; + + unsafe { + LOAD = backend; } - Some(filename) if filename.contains(".") => { - load_backend_from_dylib(&sess, &filename) + }); + let backend = unsafe { LOAD() }; + backend.init(sess); + backend +} + +fn get_trans_default() -> fn() -> Box { + // For now we only allow this function to be called once as it'll dlopen a + // few things, which seems to work best if we only do that once. In + // general this assertion never trips due to the once guard in `get_trans`, + // but there's a few manual calls to this function in this file we protect + // against. + static LOADED: AtomicBool = ATOMIC_BOOL_INIT; + assert!(!LOADED.fetch_or(true, Ordering::SeqCst), + "cannot load the default trans backend twice"); + + // When we're compiling this library with `--test` it'll run as a binary but + // not actually exercise much functionality. As a result most of the logic + // here is defunkt (it assumes we're a dynamic library in a sysroot) so + // let's just return a dummy creation function which won't be used in + // general anyway. + if cfg!(test) { + return rustc_trans_utils::trans_crate::MetadataOnlyTransCrate::new + } + + let target = session::config::host_triple(); + let mut sysroot_candidates = vec![filesearch::get_or_default_sysroot()]; + let path = current_dll_path() + .and_then(|s| s.canonicalize().ok()); + if let Some(dll) = path { + // use `parent` twice to chop off the file name and then also the + // directory containing the dll which should be either `lib` or `bin`. + if let Some(path) = dll.parent().and_then(|p| p.parent()) { + // The original `path` pointed at the `rustc_driver` crate's dll. + // Now that dll should only be in one of two locations. The first is + // in the compiler's libdir, for example `$sysroot/lib/*.dll`. The + // other is the target's libdir, for example + // `$sysroot/lib/rustlib/$target/lib/*.dll`. + // + // We don't know which, so let's assume that if our `path` above + // ends in `$target` we *could* be in the target libdir, and always + // assume that we may be in the main libdir. + sysroot_candidates.push(path.to_owned()); + + if path.ends_with(target) { + sysroot_candidates.extend(path.parent() // chop off `$target` + .and_then(|p| p.parent()) // chop off `rustlib` + .and_then(|p| p.parent()) // chop off `lib` + .map(|s| s.to_owned())); + } + } + } + + let sysroot = sysroot_candidates.iter() + .map(|sysroot| { + let libdir = filesearch::relative_target_lib_path(&sysroot, &target); + sysroot.join(&libdir).join("codegen-backends") + }) + .filter(|f| { + info!("codegen backend candidate: {}", f.display()); + f.exists() + }) + .next(); + let sysroot = match sysroot { + Some(path) => path, + None => { + let candidates = sysroot_candidates.iter() + .map(|p| p.display().to_string()) + .collect::>() + .join("\n* "); + let err = format!("failed to find a `codegen-backends` folder \ + in the sysroot candidates:\n* {}", candidates); + early_error(ErrorOutputType::default(), &err); + } + }; + info!("probing {} for a codegen backend", sysroot.display()); + + let d = match sysroot.read_dir() { + Ok(d) => d, + Err(e) => { + let err = format!("failed to load default codegen backend, couldn't \ + read `{}`: {}", sysroot.display(), e); + early_error(ErrorOutputType::default(), &err); + } + }; + + let mut file: Option = None; + + for entry in d.filter_map(|e| e.ok()) { + let path = entry.path(); + let filename = match path.file_name().and_then(|s| s.to_str()) { + Some(s) => s, + None => continue, + }; + if !(filename.starts_with(DLL_PREFIX) && filename.ends_with(DLL_SUFFIX)) { + continue + } + let name = &filename[DLL_PREFIX.len() .. filename.len() - DLL_SUFFIX.len()]; + if !name.starts_with("rustc_trans") { + continue + } + if let Some(ref prev) = file { + let err = format!("duplicate codegen backends found\n\ + first: {}\n\ + second: {}\n\ + ", prev.display(), path.display()); + early_error(ErrorOutputType::default(), &err); + } + file = Some(path.clone()); + } + + match file { + Some(ref s) => return load_backend_from_dylib(s), + None => { + let err = format!("failed to load default codegen backend, no appropriate \ + codegen dylib found in `{}`", sysroot.display()); + early_error(ErrorOutputType::default(), &err); + } + } + + #[cfg(unix)] + fn current_dll_path() -> Option { + use std::ffi::{OsStr, CStr}; + use std::os::unix::prelude::*; + + unsafe { + let addr = current_dll_path as usize as *mut _; + let mut info = mem::zeroed(); + if libc::dladdr(addr, &mut info) == 0 { + info!("dladdr failed"); + return None + } + if info.dli_fname.is_null() { + info!("dladdr returned null pointer"); + return None + } + let bytes = CStr::from_ptr(info.dli_fname).to_bytes(); + let os = OsStr::from_bytes(bytes); + Some(PathBuf::from(os)) + } + } + + #[cfg(windows)] + fn current_dll_path() -> Option { + use std::ffi::OsString; + use std::os::windows::prelude::*; + + extern "system" { + fn GetModuleHandleExW(dwFlags: u32, + lpModuleName: usize, + phModule: *mut usize) -> i32; + fn GetModuleFileNameW(hModule: usize, + lpFilename: *mut u16, + nSize: u32) -> u32; + } + + const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS: u32 = 0x00000004; + + unsafe { + let mut module = 0; + let r = GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + current_dll_path as usize, + &mut module); + if r == 0 { + info!("GetModuleHandleExW failed: {}", io::Error::last_os_error()); + return None + } + let mut space = Vec::with_capacity(1024); + let r = GetModuleFileNameW(module, + space.as_mut_ptr(), + space.capacity() as u32); + if r == 0 { + info!("GetModuleFileNameW failed: {}", io::Error::last_os_error()); + return None + } + let r = r as usize; + if r >= space.capacity() { + info!("our buffer was too small? {}", + io::Error::last_os_error()); + return None + } + space.set_len(r); + let os = OsString::from_wide(&space); + Some(PathBuf::from(os)) } - Some(trans_name) => sess.fatal(&format!("Unknown codegen backend {}", trans_name)), } } @@ -878,7 +1072,7 @@ pub fn version(binary: &str, matches: &getopts::Matches) { println!("commit-date: {}", unw(commit_date_str())); println!("host: {}", config::host_triple()); println!("release: {}", unw(release_str())); - rustc_trans::print_version(); + get_trans_default()().print_version(); } } @@ -1175,7 +1369,7 @@ pub fn handle_options(args: &[String]) -> Option { } if cg_flags.contains(&"passes=list".to_string()) { - rustc_trans::print_passes(); + get_trans_default()().print_passes(); return None; } @@ -1284,8 +1478,8 @@ pub fn diagnostics_registry() -> errors::registry::Registry { all_errors.extend_from_slice(&rustc_typeck::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS); - #[cfg(feature="llvm")] - all_errors.extend_from_slice(&rustc_trans::DIAGNOSTICS); + // FIXME: need to figure out a way to get these back in here + // all_errors.extend_from_slice(get_trans(sess).diagnostics()); all_errors.extend_from_slice(&rustc_trans_utils::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS); diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 68f4b17a6a3..4ae6a93d698 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -228,7 +228,8 @@ impl PpSourceMode { } PpmTyped => { let control = &driver::CompileController::basic(); - abort_on_err(driver::phase_3_run_analysis_passes(&*::DefaultTransCrate::new(&sess), + let trans = ::get_trans(sess); + abort_on_err(driver::phase_3_run_analysis_passes(&*trans, control, sess, cstore, @@ -1081,7 +1082,8 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, let mut out = Vec::new(); let control = &driver::CompileController::basic(); - abort_on_err(driver::phase_3_run_analysis_passes(&*::DefaultTransCrate::new(&sess), + let trans = ::get_trans(sess); + abort_on_err(driver::phase_3_run_analysis_passes(&*trans, control, sess, cstore, diff --git a/src/librustc_llvm/Cargo.toml b/src/librustc_llvm/Cargo.toml index a9566c4bcac..45e97127ede 100644 --- a/src/librustc_llvm/Cargo.toml +++ b/src/librustc_llvm/Cargo.toml @@ -7,13 +7,13 @@ build = "build.rs" [lib] name = "rustc_llvm" path = "lib.rs" -crate-type = ["dylib"] [features] static-libstdcpp = [] [dependencies] bitflags = "1.0" +libc = "0.2" rustc_cratesio_shim = { path = "../librustc_cratesio_shim" } [build-dependencies] diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 91dc3210e11..49b93f3c7d6 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -146,6 +146,7 @@ fn main() { cfg.define(&flag, None); } + println!("cargo:rerun-if-changed-env=LLVM_RUSTLLVM"); if env::var_os("LLVM_RUSTLLVM").is_some() { cfg.define("LLVM_RUSTLLVM", None); } diff --git a/src/librustc_metadata/dynamic_lib.rs b/src/librustc_metadata/dynamic_lib.rs index 1b42fa03a4f..d7da0d00012 100644 --- a/src/librustc_metadata/dynamic_lib.rs +++ b/src/librustc_metadata/dynamic_lib.rs @@ -38,7 +38,17 @@ impl DynamicLibrary { // run. match maybe_library { Err(err) => Err(err), - Ok(handle) => Ok(DynamicLibrary { handle: handle }) + Ok(handle) => Ok(DynamicLibrary { handle }) + } + } + + /// Load a dynamic library into the global namespace (RTLD_GLOBAL on Unix) + /// and do it now (don't use RTLD_LAZY on Unix). + pub fn open_global_now(filename: &Path) -> Result { + let maybe_library = dl::open_global_now(filename.as_os_str()); + match maybe_library { + Err(err) => Err(err), + Ok(handle) => Ok(DynamicLibrary { handle }) } } @@ -145,15 +155,20 @@ mod dl { }) } - const LAZY: libc::c_int = 1; + pub fn open_global_now(filename: &OsStr) -> Result<*mut u8, String> { + check_for_errors_in(|| unsafe { + let s = CString::new(filename.as_bytes()).unwrap(); + libc::dlopen(s.as_ptr(), libc::RTLD_GLOBAL | libc::RTLD_NOW) as *mut u8 + }) + } unsafe fn open_external(filename: &OsStr) -> *mut u8 { let s = CString::new(filename.as_bytes()).unwrap(); - libc::dlopen(s.as_ptr(), LAZY) as *mut u8 + libc::dlopen(s.as_ptr(), libc::RTLD_LAZY) as *mut u8 } unsafe fn open_internal() -> *mut u8 { - libc::dlopen(ptr::null(), LAZY) as *mut u8 + libc::dlopen(ptr::null(), libc::RTLD_LAZY) as *mut u8 } pub fn check_for_errors_in(f: F) -> Result where @@ -224,6 +239,10 @@ mod dl { fn FreeLibrary(handle: HMODULE) -> BOOL; } + pub fn open_global_now(filename: &OsStr) -> Result<*mut u8, String> { + open(Some(filename)) + } + pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> { // disable "dll load failed" error dialog. let prev_error_mode = unsafe { diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index 79dd57b37f4..14591de31ca 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -13,6 +13,7 @@ test = false bitflags = "1.0" flate2 = "1.0" jobserver = "0.1.5" +libc = "0.2" log = "0.4" num_cpus = "1.0" rustc = { path = "../librustc" } @@ -36,3 +37,6 @@ tempdir = "0.3" [target."cfg(windows)".dependencies] cc = "1.0.1" + +[features] +jemalloc = ["rustc_back/jemalloc"] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index b67997081aa..908d3790170 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -69,7 +69,7 @@ extern crate tempdir; use back::bytecode::RLIB_BYTECODE_EXTENSION; -pub use llvm_util::{target_features, print_version, print_passes}; +pub use llvm_util::target_features; use std::any::Any; use std::path::PathBuf; @@ -149,13 +149,16 @@ impl !Send for LlvmTransCrate {} // Llvm is on a per-thread basis impl !Sync for LlvmTransCrate {} impl LlvmTransCrate { - pub fn new(sess: &Session) -> Box { - llvm_util::init(sess); // Make sure llvm is inited + pub fn new() -> Box { box LlvmTransCrate(()) } } impl TransCrate for LlvmTransCrate { + fn init(&self, sess: &Session) { + llvm_util::init(sess); // Make sure llvm is inited + } + fn print(&self, req: PrintRequest, sess: &Session) { match req { PrintRequest::RelocationModels => { @@ -183,6 +186,19 @@ impl TransCrate for LlvmTransCrate { } } + fn print_passes(&self) { + llvm_util::print_passes(); + } + + fn print_version(&self) { + llvm_util::print_version(); + } + + #[cfg(not(stage0))] + fn diagnostics(&self) -> &[(&'static str, &'static str)] { + &DIAGNOSTICS + } + fn target_features(&self, sess: &Session) -> Vec { target_features(sess) } @@ -252,8 +268,8 @@ impl TransCrate for LlvmTransCrate { /// This is the entrypoint for a hot plugged rustc_trans #[no_mangle] -pub fn __rustc_codegen_backend(sess: &Session) -> Box { - LlvmTransCrate::new(sess) +pub fn __rustc_codegen_backend() -> Box { + LlvmTransCrate::new() } struct ModuleTranslation { diff --git a/src/librustc_trans_utils/trans_crate.rs b/src/librustc_trans_utils/trans_crate.rs index 49756d754fe..e14abdff339 100644 --- a/src/librustc_trans_utils/trans_crate.rs +++ b/src/librustc_trans_utils/trans_crate.rs @@ -48,8 +48,12 @@ use rustc_mir::monomorphize::collector; use link::{build_link_meta, out_filename}; pub trait TransCrate { + fn init(&self, _sess: &Session) {} fn print(&self, _req: PrintRequest, _sess: &Session) {} fn target_features(&self, _sess: &Session) -> Vec { vec![] } + fn print_passes(&self) {} + fn print_version(&self) {} + fn diagnostics(&self) -> &[(&'static str, &'static str)] { &[] } fn metadata_loader(&self) -> Box; fn provide(&self, _providers: &mut Providers); @@ -168,7 +172,13 @@ pub struct OngoingCrateTranslation { } impl MetadataOnlyTransCrate { - pub fn new(sess: &Session) -> Box { + pub fn new() -> Box { + box MetadataOnlyTransCrate(()) + } +} + +impl TransCrate for MetadataOnlyTransCrate { + fn init(&self, sess: &Session) { for cty in sess.opts.crate_types.iter() { match *cty { CrateType::CrateTypeRlib | CrateType::CrateTypeDylib | @@ -180,12 +190,8 @@ impl MetadataOnlyTransCrate { }, } } - - box MetadataOnlyTransCrate(()) } -} -impl TransCrate for MetadataOnlyTransCrate { fn metadata_loader(&self) -> Box { box NoLlvmMetadataLoader } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 5fe4794389f..0674a0b5a3b 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -9,7 +9,7 @@ // except according to those terms. use rustc_lint; -use rustc_driver::{driver, target_features, abort_on_err}; +use rustc_driver::{self, driver, target_features, abort_on_err}; use rustc::session::{self, config}; use rustc::hir::def_id::DefId; use rustc::hir::def::Def; @@ -18,7 +18,6 @@ use rustc::ty::{self, TyCtxt, AllArenas}; use rustc::hir::map as hir_map; use rustc::lint; use rustc::util::nodemap::FxHashMap; -use rustc_trans; use rustc_resolve as resolve; use rustc_metadata::creader::CrateLoader; use rustc_metadata::cstore::CStore; @@ -151,7 +150,7 @@ pub fn run_core(search_paths: SearchPaths, let mut sess = session::build_session_( sessopts, cpath, diagnostic_handler, codemap, ); - let trans = rustc_trans::LlvmTransCrate::new(&sess); + let trans = rustc_driver::get_trans(&sess); let cstore = Rc::new(CStore::new(trans.metadata_loader())); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index ccd79e5b2c5..e39fe20310c 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -63,8 +63,6 @@ use std::path::{Path, PathBuf}; use std::process; use std::sync::mpsc::channel; -use rustc_driver::rustc_trans; - use externalfiles::ExternalHtml; use rustc::session::search_paths::SearchPaths; use rustc::session::config::{ErrorOutputType, RustcOptGroup, nightly_options, diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 10850f88f2d..d61b80c9aa0 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -33,7 +33,6 @@ use rustc_driver::{self, driver, Compilation}; use rustc_driver::driver::phase_2_configure_and_expand; use rustc_metadata::cstore::CStore; use rustc_resolve::MakeGlobMap; -use rustc_trans; use syntax::ast; use syntax::codemap::CodeMap; use syntax::feature_gate::UnstableFeatures; @@ -84,7 +83,7 @@ pub fn run(input_path: &Path, let mut sess = session::build_session_( sessopts, Some(input_path.to_owned()), handler, codemap.clone(), ); - let trans = rustc_trans::LlvmTransCrate::new(&sess); + let trans = rustc_driver::get_trans(&sess); let cstore = Rc::new(CStore::new(trans.metadata_loader())); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); sess.parse_sess.config = @@ -249,7 +248,7 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, let mut sess = session::build_session_( sessopts, None, diagnostic_handler, codemap, ); - let trans = rustc_trans::LlvmTransCrate::new(&sess); + let trans = rustc_driver::get_trans(&sess); let cstore = Rc::new(CStore::new(trans.metadata_loader())); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); diff --git a/src/rustc/Cargo.toml b/src/rustc/Cargo.toml index d185c061d5b..bbc4c2ee43e 100644 --- a/src/rustc/Cargo.toml +++ b/src/rustc/Cargo.toml @@ -7,12 +7,9 @@ version = "0.0.0" name = "rustc" path = "rustc.rs" -# All optional dependencies so the features passed to this Cargo.toml select -# what should actually be built. [dependencies] rustc_back = { path = "../librustc_back" } rustc_driver = { path = "../librustc_driver" } [features] jemalloc = ["rustc_back/jemalloc"] -llvm = ["rustc_driver/llvm"] diff --git a/src/test/run-make/hotplug_codegen_backend/the_backend.rs b/src/test/run-make/hotplug_codegen_backend/the_backend.rs index 0de404ed249..5972149590c 100644 --- a/src/test/run-make/hotplug_codegen_backend/the_backend.rs +++ b/src/test/run-make/hotplug_codegen_backend/the_backend.rs @@ -77,6 +77,6 @@ impl TransCrate for TheBackend { /// This is the entrypoint for a hot plugged rustc_trans #[no_mangle] -pub fn __rustc_codegen_backend(sess: &Session) -> Box { - Box::new(TheBackend(MetadataOnlyTransCrate::new(sess))) +pub fn __rustc_codegen_backend() -> Box { + Box::new(TheBackend(MetadataOnlyTransCrate::new())) } diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs index c360dde618e..b4b29e15ce1 100644 --- a/src/test/run-make/issue-19371/foo.rs +++ b/src/test/run-make/issue-19371/foo.rs @@ -15,7 +15,6 @@ extern crate rustc_driver; extern crate rustc_lint; extern crate rustc_metadata; extern crate rustc_errors; -extern crate rustc_trans; extern crate rustc_trans_utils; extern crate syntax; @@ -63,7 +62,7 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc, Box) { let descriptions = Registry::new(&rustc::DIAGNOSTICS); let sess = build_session(opts, None, descriptions); - let trans = rustc_trans::LlvmTransCrate::new(&sess); + let trans = rustc_driver::get_trans(&sess); let cstore = Rc::new(CStore::new(trans.metadata_loader())); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); (sess, cstore, trans) diff --git a/src/test/run-make/llvm-pass/Makefile b/src/test/run-make/llvm-pass/Makefile index 0d31d2c8235..8a18aadf36a 100644 --- a/src/test/run-make/llvm-pass/Makefile +++ b/src/test/run-make/llvm-pass/Makefile @@ -1,5 +1,9 @@ -include ../tools.mk +ifeq ($(UNAME),Darwin) +PLUGIN_FLAGS := -C link-args=-Wl,-undefined,dynamic_lookup +endif + ifeq ($(findstring stage1,$(RUST_BUILD_STAGE)),stage1) # ignore stage1 all: @@ -11,7 +15,7 @@ ifdef IS_WINDOWS all: else all: $(call NATIVE_STATICLIB,llvm-function-pass) $(call NATIVE_STATICLIB,llvm-module-pass) - $(RUSTC) plugin.rs -C prefer-dynamic + $(RUSTC) plugin.rs -C prefer-dynamic $(PLUGIN_FLAGS) $(RUSTC) main.rs $(TMPDIR)/libllvm-function-pass.o: diff --git a/src/test/run-make/llvm-pass/plugin.rs b/src/test/run-make/llvm-pass/plugin.rs index 37aab2bbd05..f77b2fca857 100644 --- a/src/test/run-make/llvm-pass/plugin.rs +++ b/src/test/run-make/llvm-pass/plugin.rs @@ -14,7 +14,6 @@ extern crate rustc; extern crate rustc_plugin; -extern crate rustc_trans; #[link(name = "llvm-function-pass", kind = "static")] #[link(name = "llvm-module-pass", kind = "static")] diff --git a/src/test/run-pass-fulldeps/create-dir-all-bare.rs b/src/test/run-pass-fulldeps/create-dir-all-bare.rs index ba42cb870c9..a35eed1f72d 100644 --- a/src/test/run-pass-fulldeps/create-dir-all-bare.rs +++ b/src/test/run-pass-fulldeps/create-dir-all-bare.rs @@ -8,18 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-cross-compile - -#![feature(rustc_private)] - -extern crate tempdir; - use std::env; use std::fs; -use tempdir::TempDir; +use std::path::PathBuf; fn main() { - let td = TempDir::new("create-dir-all-bare").unwrap(); - env::set_current_dir(td.path()).unwrap(); + let path = PathBuf::from(env::var_os("RUST_TEST_TMPDIR").unwrap()); + env::set_current_dir(&path).unwrap(); fs::create_dir_all("create-dir-all-bare").unwrap(); } diff --git a/src/test/run-pass-fulldeps/issue-15149.rs b/src/test/run-pass-fulldeps/issue-15149.rs index 121fd4a9825..15ac1d55cc8 100644 --- a/src/test/run-pass-fulldeps/issue-15149.rs +++ b/src/test/run-pass-fulldeps/issue-15149.rs @@ -11,15 +11,11 @@ // no-prefer-dynamic // ignore-cross-compile -#![feature(rustc_private)] - -extern crate tempdir; - use std::env; use std::fs; use std::process; use std::str; -use tempdir::TempDir; +use std::path::PathBuf; fn main() { // If we're the child, make sure we were invoked correctly @@ -41,8 +37,9 @@ fn test() { let my_path = env::current_exe().unwrap(); let my_dir = my_path.parent().unwrap(); - let child_dir = TempDir::new_in(&my_dir, "issue-15140-child").unwrap(); - let child_dir = child_dir.path(); + let child_dir = PathBuf::from(env::var_os("RUST_TEST_TMPDIR").unwrap()); + let child_dir = child_dir.join("issue-15140-child"); + fs::create_dir_all(&child_dir).unwrap(); let child_path = child_dir.join(&format!("mytest{}", env::consts::EXE_SUFFIX)); @@ -63,11 +60,4 @@ fn test() { format!("child assertion failed\n child stdout:\n {}\n child stderr:\n {}", str::from_utf8(&child_output.stdout).unwrap(), str::from_utf8(&child_output.stderr).unwrap())); - - let res = fs::remove_dir_all(&child_dir); - if res.is_err() { - // On Windows deleting just executed mytest.exe can fail because it's still locked - std::thread::sleep_ms(1000); - fs::remove_dir_all(&child_dir).unwrap(); - } } diff --git a/src/test/run-pass-fulldeps/rename-directory.rs b/src/test/run-pass-fulldeps/rename-directory.rs index 7a2a4343522..417707e8932 100644 --- a/src/test/run-pass-fulldeps/rename-directory.rs +++ b/src/test/run-pass-fulldeps/rename-directory.rs @@ -13,17 +13,13 @@ // ignore-cross-compile -#![feature(rustc_private)] - -extern crate tempdir; - +use std::env; use std::ffi::CString; use std::fs::{self, File}; -use tempdir::TempDir; +use std::path::PathBuf; fn rename_directory() { - let tmpdir = TempDir::new("rename_directory").ok().expect("rename_directory failed"); - let tmpdir = tmpdir.path(); + let tmpdir = PathBuf::from(env::var_os("RUST_TEST_TMPDIR").unwrap()); let old_path = tmpdir.join("foo/bar/baz"); fs::create_dir_all(&old_path).unwrap(); let test_file = &old_path.join("temp.txt"); diff --git a/src/test/run-pass-fulldeps/stdio-from.rs b/src/test/run-pass-fulldeps/stdio-from.rs index 535ab711f5b..5b28ce0f0c6 100644 --- a/src/test/run-pass-fulldeps/stdio-from.rs +++ b/src/test/run-pass-fulldeps/stdio-from.rs @@ -10,17 +10,12 @@ // ignore-cross-compile -#![feature(rustc_private)] - -extern crate tempdir; - use std::env; use std::fs::File; use std::io; use std::io::{Read, Write}; use std::process::{Command, Stdio}; - -use tempdir::TempDir; +use std::path::PathBuf; fn main() { if env::args().len() > 1 { @@ -31,9 +26,9 @@ fn main() { } fn parent() -> io::Result<()> { - let td = TempDir::new("foo").unwrap(); - let input = td.path().join("input"); - let output = td.path().join("output"); + let td = PathBuf::from(env::var_os("RUST_TEST_TMPDIR").unwrap()); + let input = td.join("stdio-from-input"); + let output = td.join("stdio-from-output"); File::create(&input)?.write_all(b"foo\n")?; diff --git a/src/test/run-pass-fulldeps/switch-stdout.rs b/src/test/run-pass-fulldeps/switch-stdout.rs index 16f7e283285..316b97f17ef 100644 --- a/src/test/run-pass-fulldeps/switch-stdout.rs +++ b/src/test/run-pass-fulldeps/switch-stdout.rs @@ -8,14 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_private)] - -extern crate tempdir; - +use std::env; use std::fs::File; use std::io::{Read, Write}; - -use tempdir::TempDir; +use std::path::PathBuf; #[cfg(unix)] fn switch_stdout_to(file: File) { @@ -48,8 +44,8 @@ fn switch_stdout_to(file: File) { } fn main() { - let td = TempDir::new("foo").unwrap(); - let path = td.path().join("bar"); + let path = PathBuf::from(env::var_os("RUST_TEST_TMPDIR").unwrap()); + let path = path.join("switch-stdout-output"); let f = File::create(&path).unwrap(); println!("foo"); diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 533aaf9cd27..b98a4248d81 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -667,9 +667,16 @@ fn up_to_date(config: &Config, testpaths: &TestPaths, props: &EarlyProps) -> boo for pretty_printer_file in &pretty_printer_files { inputs.push(mtime(&rust_src_dir.join(pretty_printer_file))); } - for lib in config.run_lib_path.read_dir().unwrap() { - let lib = lib.unwrap(); - inputs.push(mtime(&lib.path())); + let mut entries = config.run_lib_path.read_dir().unwrap() + .collect::>(); + while let Some(entry) = entries.pop() { + let entry = entry.unwrap(); + let path = entry.path(); + if entry.metadata().unwrap().is_file() { + inputs.push(mtime(&path)); + } else { + entries.extend(path.read_dir().unwrap()); + } } if let Some(ref rustdoc_path) = config.rustdoc_path { inputs.push(mtime(&rustdoc_path));