diff options
author | Alex Crichton <alex@alexcrichton.com> | 2018-01-22 07:29:24 -0800 |
---|---|---|
committer | Alex Crichton <alex@alexcrichton.com> | 2018-01-27 19:16:21 -0800 |
commit | 884715c65420141dc06753f242a224462b120109 (patch) | |
tree | a965ef66c12ca076d0f0d08a0ae9bbea302167d6 | |
parent | bacb5c58dfdde7c35e99b2b0d8171238cc33cf6c (diff) | |
download | rust-884715c65420141dc06753f242a224462b120109.tar.gz |
rustc: Load the `rustc_trans` crate at runtime
Building on the work of # 45684 this commit updates the compiler to
unconditionally load the `rustc_trans` crate at runtime instead of linking to it
at compile time. The end goal of this work is to implement # 46819 where rustc
will have multiple backends available to it to load.
This commit starts off by removing the `extern crate rustc_trans` from the
driver. This involved moving some miscellaneous functionality into the
`TransCrate` trait and also required an implementation of how to locate and load
the trans backend. This ended up being a little tricky because the sysroot isn't
always the right location (for example `--sysroot` arguments) so some extra code
was added as well to probe a directory relative to the current dll (the
rustc_driver dll).
Rustbuild has been updated accordingly as well to have a separate compilation
invocation for the `rustc_trans` crate and assembly it accordingly into the
sysroot. Finally, the distribution logic for the `rustc` package was also
updated to slurp up the trans backends folder.
A number of assorted fallout changes were included here as well to ensure tests
pass and such, and they should all be commented inline.
33 files changed, 553 insertions, 202 deletions
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<String>, - 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<String>, +} + +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<String>) -> PathBuf { @@ -619,9 +729,20 @@ pub fn librustc_stamp(build: &Build, compiler: Compiler, target: Interned<String build.cargo_out(compiler, Mode::Librustc, target).join(".librustc.stamp") } -fn compiler_file(compiler: &Path, file: &str) -> PathBuf { - let out = output(Command::new(compiler) - .arg(format!("-print-file-name={}", file))); +pub fn librustc_trans_stamp(build: &Build, + compiler: Compiler, + target: Interned<String>) -> PathBuf { + build.cargo_out(compiler, Mode::Librustc, target).join(".librustc_trans.stamp") +} + +fn compiler_file(build: &Build, + compiler: &Path, + target: Interned<String>, + 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<F>(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; +fn load_backend_from_dylib(path: &Path) -> fn() -> Box<TransCrate> { + // 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) => { + 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); + } + } + } +} -#[cfg(not(feature="llvm"))] -pub mod rustc_trans { - pub use rustc_trans_utils::trans_crate::MetadataOnlyTransCrate as LlvmTransCrate; +pub fn get_trans(sess: &Session) -> Box<TransCrate> { + static INIT: Once = ONCE_INIT; + static mut LOAD: fn() -> Box<TransCrate> = || 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)); + } + }; - pub fn print_version() {} - pub fn print_passes() {} + unsafe { + LOAD = backend; + } + }); + let backend = unsafe { LOAD() }; + backend.init(sess); + backend } -fn load_backend_from_dylib(sess: &Session, backend_name: &str) -> Box<TransCrate> { - 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<TransCrate>; - __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 get_trans_default() -> fn() -> Box<TransCrate> { + // 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())); } } - Err(err) => { - sess.fatal(&format!("Couldnt load codegen backend {:?}: {:?}", backend_name, err)); + } + + 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::<Vec<_>>() + .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<PathBuf> = 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()); } -} -pub fn get_trans(sess: &Session) -> Box<TransCrate> { - 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) + 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); } - Some(filename) if filename.contains(".") => { - load_backend_from_dylib(&sess, &filename) + } + + #[cfg(unix)] + fn current_dll_path() -> Option<PathBuf> { + 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<PathBuf> { + 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<getopts::Matches> { } 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<DynamicLibrary, String> { + 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<T, F>(f: F) -> Result<T, String> 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<TransCrate> { - llvm_util::init(sess); // Make sure llvm is inited + pub fn new() -> Box<TransCrate> { 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<Symbol> { 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<TransCrate> { - LlvmTransCrate::new(sess) +pub fn __rustc_codegen_backend() -> Box<TransCrate> { + 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<Symbol> { vec![] } + fn print_passes(&self) {} + fn print_version(&self) {} + fn diagnostics(&self) -> &[(&'static str, &'static str)] { &[] } fn metadata_loader(&self) -> Box<MetadataLoader>; fn provide(&self, _providers: &mut Providers); @@ -168,7 +172,13 @@ pub struct OngoingCrateTranslation { } impl MetadataOnlyTransCrate { - pub fn new(sess: &Session) -> Box<TransCrate> { + pub fn new() -> Box<TransCrate> { + 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<MetadataLoader> { 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<TransCrate> { - Box::new(TheBackend(MetadataOnlyTransCrate::new(sess))) +pub fn __rustc_codegen_backend() -> Box<TransCrate> { + 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<CStore>, Box<TransCrate>) { 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::<Vec<_>>(); + 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)); |