Skip to content

Commit

Permalink
Auto merge of #47671 - alexcrichton:trans-c-api-only, r=Mark-Simulacrum
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bors committed Jan 28, 2018
2 parents 6beb06e + 884715c commit 87990a1
Show file tree
Hide file tree
Showing 33 changed files with 553 additions and 202 deletions.
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
Expand Up @@ -4,6 +4,7 @@ members = [
"rustc",
"libstd",
"libtest",
"librustc_trans",
"tools/cargotest",
"tools/clippy",
"tools/compiletest",
Expand Down
2 changes: 1 addition & 1 deletion src/bootstrap/check.rs
Expand Up @@ -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),
Expand Down
234 changes: 184 additions & 50 deletions src/bootstrap/compile.rs
Expand Up @@ -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));
}
}
}
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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),
Expand All @@ -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())
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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())
}

Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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));
Expand Down
13 changes: 12 additions & 1 deletion src/bootstrap/dist.rs
Expand Up @@ -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");
Expand Down Expand Up @@ -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")
Expand Down
2 changes: 1 addition & 1 deletion src/bootstrap/doc.rs
Expand Up @@ -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
Expand Down
3 changes: 0 additions & 3 deletions src/bootstrap/lib.rs
Expand Up @@ -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
}

Expand Down

0 comments on commit 87990a1

Please sign in to comment.