Skip to content

rustc: Load the rustc_trans crate at runtime #47671

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 28, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/Cargo.toml
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ members = [
"rustc",
"libstd",
"libtest",
"librustc_trans",
"tools/cargotest",
"tools/clippy",
"tools/compiletest",
2 changes: 1 addition & 1 deletion src/bootstrap/check.rs
Original file line number Diff line number Diff line change
@@ -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),
234 changes: 184 additions & 50 deletions src/bootstrap/compile.rs
Original file line number Diff line number Diff line change
@@ -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));
13 changes: 12 additions & 1 deletion src/bootstrap/dist.rs
Original file line number Diff line number Diff line change
@@ -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")
2 changes: 1 addition & 1 deletion src/bootstrap/doc.rs
Original file line number Diff line number Diff line change
@@ -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
3 changes: 0 additions & 3 deletions src/bootstrap/lib.rs
Original file line number Diff line number Diff line change
@@ -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
}

5 changes: 0 additions & 5 deletions src/bootstrap/native.rs
Original file line number Diff line number Diff line change
@@ -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) {
4 changes: 3 additions & 1 deletion src/bootstrap/test.rs
Original file line number Diff line number Diff line change
@@ -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"),
3 changes: 1 addition & 2 deletions src/librustc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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.
#
6 changes: 1 addition & 5 deletions src/librustc_driver/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"]
290 changes: 242 additions & 48 deletions src/librustc_driver/lib.rs
Original file line number Diff line number Diff line change
@@ -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());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a function that should lie on the trait -- it seems like it should anyway, or maybe the trait could return a vec of errors that need to be added.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heh it actually is! Unfortunately though there's not a great way to load it here, so I figured that for the one extended error in librustc_trans we could fudge it for now and figure it out later.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we just load all of the diagnostics, independent of backend, and then just some of them would be unused?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately that's also gonna be difficult I think. I believe that with this PR as-is we could do that, but in the future I think we'll only want to dlopen one version of LLVM into the current process, and at this point in time we don't actually know the trans backend we'd otherwise be using. That means that with the Emscripten target we'd load the normal LLVM backend to load diagnostics and then load the Emscripten backend to actually do trans. I think that it would work ok? The "global" nature of the dlopen though required here though may throw a wrench into that..

In essence though I don't think there's a quick fix or an easy workaround for this, we'll want to deal with it later I think.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh also note that I added a dynamic assertion for this, the business with the LOADED constant, which asserts that we only load a backend once.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, yeah, I understand that we don't want to dlopen multiple rustc_trans backends, but I was rather suggesting that we put all the diagnostic definition in driver and then the backend would use whichever ones it needed, though not all. This does increase the API surface of driver.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The diagnostics can probably be moved to the librustc_mir/monomorphize instance collector, so they're shared by all backends.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes indeed, such a strategy would for sure work!

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);
6 changes: 4 additions & 2 deletions src/librustc_driver/pretty.rs
Original file line number Diff line number Diff line change
@@ -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,
2 changes: 1 addition & 1 deletion src/librustc_llvm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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]
1 change: 1 addition & 0 deletions src/librustc_llvm/build.rs
Original file line number Diff line number Diff line change
@@ -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);
}
27 changes: 23 additions & 4 deletions src/librustc_metadata/dynamic_lib.rs
Original file line number Diff line number Diff line change
@@ -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 {
4 changes: 4 additions & 0 deletions src/librustc_trans/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"]
26 changes: 21 additions & 5 deletions src/librustc_trans/lib.rs
Original file line number Diff line number Diff line change
@@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fine for now but in the future we might want to have a Session created by the time we create this trait object (we'll need at least the target spec loaded).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe let __rustc_codegen_backend take a Option<&Session> as argument and pass None when we are only using it for printing version info and stuff like that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I think we can always create a Session, there shouldn't really be a significant cost to it since we're already doing the argument parsing and we have to load the target specs anyway.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah so the two locations this was necessary (not taking a Session on construction) was when we print the version and when we print the LLVM passes. There's also one where we need to construct a list of all error codes but that's commented out for now...

I it'd be possible to have a Session here, but it'd be a "dummy session" in some cases because I don't think we want to generate an error for failure to parse command line arguments before we print the version. Either way I'd be fine though!

Copy link
Member

@eddyb eddyb Jan 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't fully parse arguments before processing the version? Is it a separate codepath?

EDIT: note that you can't load the backend without also parsing --target / -Z codegen-backend at least.

Copy link
Member

@eddyb eddyb Jan 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well this PR doesn't use target specs yet, so it's not necessary for now. But I am curious, because I was hoping for a straight-forward implementation, is the "printing the version skips checking the rest of the CLI arguments" guaranteed/relied upon?

EDIT: I guess one could argue that -Z codegen-backend should be taken into account.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it basically would just require more refactoring. We'd have to, for example, initialize the Session in stages, first with a bunch of known options, then do some processing, then aftewards actually validate everything. AFAIK it's not really set up to do that yet.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we validate everything early and buffer the errors or something?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess? Again though I didn't get the impression that the argument parsing was at all ready for this sort of refactoring, in the sense that it seemed outside the scope of this PR

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I don't want to block this PR, this is more for future reference.

}

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 {
16 changes: 11 additions & 5 deletions src/librustc_trans_utils/trans_crate.rs
Original file line number Diff line number Diff line change
@@ -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
}
5 changes: 2 additions & 3 deletions src/librustdoc/core.rs
Original file line number Diff line number Diff line change
@@ -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));

2 changes: 0 additions & 2 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
@@ -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,
5 changes: 2 additions & 3 deletions src/librustdoc/test.rs
Original file line number Diff line number Diff line change
@@ -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));

3 changes: 0 additions & 3 deletions src/rustc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"]
4 changes: 2 additions & 2 deletions src/test/run-make/hotplug_codegen_backend/the_backend.rs
Original file line number Diff line number Diff line change
@@ -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()))
}
3 changes: 1 addition & 2 deletions src/test/run-make/issue-19371/foo.rs
Original file line number Diff line number Diff line change
@@ -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)
6 changes: 5 additions & 1 deletion src/test/run-make/llvm-pass/Makefile
Original file line number Diff line number Diff line change
@@ -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:
1 change: 0 additions & 1 deletion src/test/run-make/llvm-pass/plugin.rs
Original file line number Diff line number Diff line change
@@ -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")]
12 changes: 3 additions & 9 deletions src/test/run-pass-fulldeps/create-dir-all-bare.rs
Original file line number Diff line number Diff line change
@@ -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();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these changes necessary? Can we no longer link to tempdir from tests? Or is it that tempdir wasn't being rebuilt because rustbuild is buggy (I would not be surprised).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dependencies of librustc_trans are no longer available in the sysroot (as we just manually copy the one DLL), and one of its dependencies was tempdir. (no other crates in rustc use tempdir)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I recall, the previous solution to this "problem" would be to move tempdir to a dependency of librustc. I'm fine with this too though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's true yeah we could do that but I'm also always a fan of tests with fewer dependencies :)

fs::create_dir_all("create-dir-all-bare").unwrap();
}
18 changes: 4 additions & 14 deletions src/test/run-pass-fulldeps/issue-15149.rs
Original file line number Diff line number Diff line change
@@ -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();
}
}
10 changes: 3 additions & 7 deletions src/test/run-pass-fulldeps/rename-directory.rs
Original file line number Diff line number Diff line change
@@ -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");
13 changes: 4 additions & 9 deletions src/test/run-pass-fulldeps/stdio-from.rs
Original file line number Diff line number Diff line change
@@ -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")?;

12 changes: 4 additions & 8 deletions src/test/run-pass-fulldeps/switch-stdout.rs
Original file line number Diff line number Diff line change
@@ -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");
13 changes: 10 additions & 3 deletions src/tools/compiletest/src/main.rs
Original file line number Diff line number Diff line change
@@ -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));