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.
This commit is contained in:
Alex Crichton 2018-01-22 07:29:24 -08:00
parent bacb5c58df
commit 884715c654
33 changed files with 556 additions and 205 deletions

3
src/Cargo.lock generated
View File

@ -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",

View File

@ -4,6 +4,7 @@ members = [
"rustc",
"libstd",
"libtest",
"librustc_trans",
"tools/cargotest",
"tools/clippy",
"tools/compiletest",

View File

@ -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),

View File

@ -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));

View File

@ -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")

View File

@ -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

View File

@ -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
}

View File

@ -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) {

View File

@ -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"),

View File

@ -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.
#

View File

@ -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"]

View File

@ -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;
#[cfg(not(feature="llvm"))]
pub mod rustc_trans {
pub use rustc_trans_utils::trans_crate::MetadataOnlyTransCrate as LlvmTransCrate;
pub fn print_version() {}
pub fn print_passes() {}
}
fn load_backend_from_dylib(sess: &Session, backend_name: &str) -> Box<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 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) => {
sess.fatal(&format!("Couldnt load codegen backend {:?}: {:?}", backend_name, err));
let err = format!("couldn't load codegen backend {:?}: {:?}",
path,
err);
early_error(ErrorOutputType::default(), &err);
}
};
unsafe {
match lib.symbol("__rustc_codegen_backend") {
Ok(f) => {
mem::forget(lib);
mem::transmute::<*mut u8, _>(f)
}
Err(e) => {
let err = format!("couldn't load codegen backend as it \
doesn't export the `__rustc_codegen_backend` \
symbol: {:?}", e);
early_error(ErrorOutputType::default(), &err);
}
}
}
}
pub fn get_trans(sess: &Session) -> Box<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)
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));
}
};
unsafe {
LOAD = backend;
}
Some(filename) if filename.contains(".") => {
load_backend_from_dylib(&sess, &filename)
});
let backend = unsafe { LOAD() };
backend.init(sess);
backend
}
fn get_trans_default() -> fn() -> Box<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()));
}
}
}
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());
}
match file {
Some(ref s) => return load_backend_from_dylib(s),
None => {
let err = format!("failed to load default codegen backend, no appropriate \
codegen dylib found in `{}`", sysroot.display());
early_error(ErrorOutputType::default(), &err);
}
}
#[cfg(unix)]
fn current_dll_path() -> Option<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);

View File

@ -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,

View File

@ -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]

View File

@ -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);
}

View File

@ -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 {

View File

@ -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"]

View File

@ -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 {

View File

@ -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
}

View File

@ -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));

View File

@ -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,

View File

@ -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));

View File

@ -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"]

View File

@ -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()))
}

View File

@ -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)

View File

@ -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:

View File

@ -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")]

View File

@ -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();
}

View File

@ -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();
}
}

View File

@ -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");

View File

@ -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")?;

View File

@ -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");

View File

@ -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));