Skip to content

Commit 87990a1

Browse files
committed
Auto merge of #47671 - alexcrichton:trans-c-api-only, r=Mark-Simulacrum
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.
2 parents 6beb06e + 884715c commit 87990a1

File tree

33 files changed

+553
-202
lines changed

33 files changed

+553
-202
lines changed

src/Cargo.lock

+2-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ members = [
44
"rustc",
55
"libstd",
66
"libtest",
7+
"librustc_trans",
78
"tools/cargotest",
89
"tools/clippy",
910
"tools/compiletest",

src/bootstrap/check.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ impl Step for Rustc {
9494
build.clear_if_dirty(&stage_out, &libtest_stamp(build, compiler, target));
9595

9696
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check");
97-
rustc_cargo(build, target, &mut cargo);
97+
rustc_cargo(build, &mut cargo);
9898
run_cargo(build,
9999
&mut cargo,
100100
&librustc_stamp(build, compiler, target),

src/bootstrap/compile.rs

+184-50
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,11 @@ impl Step for StartupObjects {
300300
}
301301

302302
for obj in ["crt2.o", "dllcrt2.o"].iter() {
303-
copy(&compiler_file(build.cc(target), obj), &sysroot_dir.join(obj));
303+
let src = compiler_file(build,
304+
build.cc(target),
305+
target,
306+
obj);
307+
copy(&src, &sysroot_dir.join(obj));
304308
}
305309
}
306310
}
@@ -454,10 +458,6 @@ impl Step for Rustc {
454458

455459
builder.ensure(Test { compiler, target });
456460

457-
// Build LLVM for our target. This will implicitly build the host LLVM
458-
// if necessary.
459-
builder.ensure(native::Llvm { target });
460-
461461
if build.force_use_stage1(compiler, target) {
462462
builder.ensure(Rustc {
463463
compiler: builder.compiler(1, build.build),
@@ -487,7 +487,7 @@ impl Step for Rustc {
487487
build.clear_if_dirty(&stage_out, &libtest_stamp(build, compiler, target));
488488

489489
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build");
490-
rustc_cargo(build, target, &mut cargo);
490+
rustc_cargo(build, &mut cargo);
491491
run_cargo(build,
492492
&mut cargo,
493493
&librustc_stamp(build, compiler, target),
@@ -501,14 +501,14 @@ impl Step for Rustc {
501501
}
502502
}
503503

504-
/// Same as `std_cargo`, but for libtest
505-
pub fn rustc_cargo(build: &Build,
506-
target: Interned<String>,
507-
cargo: &mut Command) {
504+
pub fn rustc_cargo(build: &Build, cargo: &mut Command) {
508505
cargo.arg("--features").arg(build.rustc_features())
509506
.arg("--manifest-path")
510507
.arg(build.src.join("src/rustc/Cargo.toml"));
508+
rustc_cargo_env(build, cargo);
509+
}
511510

511+
fn rustc_cargo_env(build: &Build, cargo: &mut Command) {
512512
// Set some configuration variables picked up by build scripts and
513513
// the compiler alike
514514
cargo.env("CFG_RELEASE", build.rust_release())
@@ -536,27 +536,6 @@ pub fn rustc_cargo(build: &Build,
536536
if !build.unstable_features() {
537537
cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1");
538538
}
539-
// Flag that rust llvm is in use
540-
if build.is_rust_llvm(target) {
541-
cargo.env("LLVM_RUSTLLVM", "1");
542-
}
543-
cargo.env("LLVM_CONFIG", build.llvm_config(target));
544-
let target_config = build.config.target_config.get(&target);
545-
if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
546-
cargo.env("CFG_LLVM_ROOT", s);
547-
}
548-
// Building with a static libstdc++ is only supported on linux right now,
549-
// not for MSVC or macOS
550-
if build.config.llvm_static_stdcpp &&
551-
!target.contains("freebsd") &&
552-
!target.contains("windows") &&
553-
!target.contains("apple") {
554-
cargo.env("LLVM_STATIC_STDCPP",
555-
compiler_file(build.cxx(target).unwrap(), "libstdc++.a"));
556-
}
557-
if build.config.llvm_link_shared {
558-
cargo.env("LLVM_LINK_SHARED", "1");
559-
}
560539
if let Some(ref s) = build.config.rustc_default_linker {
561540
cargo.env("CFG_DEFAULT_LINKER", s);
562541
}
@@ -601,6 +580,137 @@ impl Step for RustcLink {
601580
}
602581
}
603582

583+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
584+
pub struct RustcTrans {
585+
pub compiler: Compiler,
586+
pub target: Interned<String>,
587+
}
588+
589+
impl Step for RustcTrans {
590+
type Output = ();
591+
const ONLY_HOSTS: bool = true;
592+
const DEFAULT: bool = true;
593+
594+
fn should_run(run: ShouldRun) -> ShouldRun {
595+
run.path("src/librustc_trans").krate("rustc_trans")
596+
}
597+
598+
fn make_run(run: RunConfig) {
599+
run.builder.ensure(RustcTrans {
600+
compiler: run.builder.compiler(run.builder.top_stage, run.host),
601+
target: run.target,
602+
});
603+
}
604+
605+
fn run(self, builder: &Builder) {
606+
let build = builder.build;
607+
let compiler = self.compiler;
608+
let target = self.target;
609+
610+
builder.ensure(Rustc { compiler, target });
611+
612+
// Build LLVM for our target. This will implicitly build the host LLVM
613+
// if necessary.
614+
builder.ensure(native::Llvm { target });
615+
616+
if build.force_use_stage1(compiler, target) {
617+
builder.ensure(RustcTrans {
618+
compiler: builder.compiler(1, build.build),
619+
target,
620+
});
621+
return;
622+
}
623+
624+
let _folder = build.fold_output(|| format!("stage{}-rustc_trans", compiler.stage));
625+
println!("Building stage{} trans artifacts ({} -> {})",
626+
compiler.stage, &compiler.host, target);
627+
628+
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build");
629+
cargo.arg("--manifest-path")
630+
.arg(build.src.join("src/librustc_trans/Cargo.toml"))
631+
.arg("--features").arg(build.rustc_features());
632+
rustc_cargo_env(build, &mut cargo);
633+
634+
// Pass down configuration from the LLVM build into the build of
635+
// librustc_llvm and librustc_trans.
636+
if build.is_rust_llvm(target) {
637+
cargo.env("LLVM_RUSTLLVM", "1");
638+
}
639+
cargo.env("LLVM_CONFIG", build.llvm_config(target));
640+
let target_config = build.config.target_config.get(&target);
641+
if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
642+
cargo.env("CFG_LLVM_ROOT", s);
643+
}
644+
// Building with a static libstdc++ is only supported on linux right now,
645+
// not for MSVC or macOS
646+
if build.config.llvm_static_stdcpp &&
647+
!target.contains("freebsd") &&
648+
!target.contains("windows") &&
649+
!target.contains("apple") {
650+
let file = compiler_file(build,
651+
build.cxx(target).unwrap(),
652+
target,
653+
"libstdc++.a");
654+
cargo.env("LLVM_STATIC_STDCPP", file);
655+
}
656+
if build.config.llvm_link_shared {
657+
cargo.env("LLVM_LINK_SHARED", "1");
658+
}
659+
660+
run_cargo(build,
661+
&mut cargo,
662+
&librustc_trans_stamp(build, compiler, target),
663+
false);
664+
}
665+
}
666+
667+
/// Creates the `codegen-backends` folder for a compiler that's about to be
668+
/// assembled as a complete compiler.
669+
///
670+
/// This will take the codegen artifacts produced by `compiler` and link them
671+
/// into an appropriate location for `target_compiler` to be a functional
672+
/// compiler.
673+
fn copy_codegen_backends_to_sysroot(builder: &Builder,
674+
compiler: Compiler,
675+
target_compiler: Compiler) {
676+
let build = builder.build;
677+
let target = target_compiler.host;
678+
679+
// Note that this step is different than all the other `*Link` steps in
680+
// that it's not assembling a bunch of libraries but rather is primarily
681+
// moving the codegen backend into place. The codegen backend of rustc is
682+
// not linked into the main compiler by default but is rather dynamically
683+
// selected at runtime for inclusion.
684+
//
685+
// Here we're looking for the output dylib of the `RustcTrans` step and
686+
// we're copying that into the `codegen-backends` folder.
687+
let libdir = builder.sysroot_libdir(target_compiler, target);
688+
let dst = libdir.join("codegen-backends");
689+
t!(fs::create_dir_all(&dst));
690+
let stamp = librustc_trans_stamp(build, compiler, target);
691+
692+
let mut copied = None;
693+
for file in read_stamp_file(&stamp) {
694+
let filename = match file.file_name().and_then(|s| s.to_str()) {
695+
Some(s) => s,
696+
None => continue,
697+
};
698+
if !is_dylib(filename) || !filename.contains("rustc_trans-") {
699+
continue
700+
}
701+
match copied {
702+
None => copied = Some(file.clone()),
703+
Some(ref s) => {
704+
panic!("copied two codegen backends:\n{}\n{}",
705+
s.display(),
706+
file.display());
707+
}
708+
}
709+
copy(&file, &dst.join(filename));
710+
}
711+
assert!(copied.is_some(), "failed to find a codegen backend to copy");
712+
}
713+
604714
/// Cargo's output path for the standard library in a given stage, compiled
605715
/// by a particular compiler for the specified target.
606716
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
619729
build.cargo_out(compiler, Mode::Librustc, target).join(".librustc.stamp")
620730
}
621731

622-
fn compiler_file(compiler: &Path, file: &str) -> PathBuf {
623-
let out = output(Command::new(compiler)
624-
.arg(format!("-print-file-name={}", file)));
732+
pub fn librustc_trans_stamp(build: &Build,
733+
compiler: Compiler,
734+
target: Interned<String>) -> PathBuf {
735+
build.cargo_out(compiler, Mode::Librustc, target).join(".librustc_trans.stamp")
736+
}
737+
738+
fn compiler_file(build: &Build,
739+
compiler: &Path,
740+
target: Interned<String>,
741+
file: &str) -> PathBuf {
742+
let mut cmd = Command::new(compiler);
743+
cmd.args(build.cflags(target));
744+
cmd.arg(format!("-print-file-name={}", file));
745+
let out = output(&mut cmd);
625746
PathBuf::from(out.trim())
626747
}
627748

@@ -690,20 +811,23 @@ impl Step for Assemble {
690811
}
691812

692813
// Get the compiler that we'll use to bootstrap ourselves.
693-
let build_compiler = if target_compiler.host != build.build {
694-
// Build a compiler for the host platform. We cannot use the stage0
695-
// compiler for the host platform for this because it doesn't have
696-
// the libraries we need. FIXME: Perhaps we should download those
697-
// libraries? It would make builds faster...
698-
// FIXME: It may be faster if we build just a stage 1
699-
// compiler and then use that to bootstrap this compiler
700-
// forward.
701-
builder.compiler(target_compiler.stage - 1, build.build)
702-
} else {
703-
// Build the compiler we'll use to build the stage requested. This
704-
// may build more than one compiler (going down to stage 0).
705-
builder.compiler(target_compiler.stage - 1, target_compiler.host)
706-
};
814+
//
815+
// Note that this is where the recursive nature of the bootstrap
816+
// happens, as this will request the previous stage's compiler on
817+
// downwards to stage 0.
818+
//
819+
// Also note that we're building a compiler for the host platform. We
820+
// only assume that we can run `build` artifacts, which means that to
821+
// produce some other architecture compiler we need to start from
822+
// `build` to get there.
823+
//
824+
// FIXME: Perhaps we should download those libraries?
825+
// It would make builds faster...
826+
//
827+
// FIXME: It may be faster if we build just a stage 1 compiler and then
828+
// use that to bootstrap this compiler forward.
829+
let build_compiler =
830+
builder.compiler(target_compiler.stage - 1, build.build);
707831

708832
// Build the libraries for this compiler to link to (i.e., the libraries
709833
// it uses at runtime). NOTE: Crates the target compiler compiles don't
@@ -721,7 +845,14 @@ impl Step for Assemble {
721845
builder.ensure(RustcLink { compiler, target_compiler, target });
722846
}
723847
} else {
724-
builder.ensure(Rustc { compiler: build_compiler, target: target_compiler.host });
848+
builder.ensure(Rustc {
849+
compiler: build_compiler,
850+
target: target_compiler.host,
851+
});
852+
builder.ensure(RustcTrans {
853+
compiler: build_compiler,
854+
target: target_compiler.host,
855+
});
725856
}
726857

727858
let stage = target_compiler.stage;
@@ -740,9 +871,12 @@ impl Step for Assemble {
740871
}
741872
}
742873

743-
let out_dir = build.cargo_out(build_compiler, Mode::Librustc, host);
874+
copy_codegen_backends_to_sysroot(builder,
875+
build_compiler,
876+
target_compiler);
744877

745878
// Link the compiler binary itself into place
879+
let out_dir = build.cargo_out(build_compiler, Mode::Librustc, host);
746880
let rustc = out_dir.join(exe("rustc", &*host));
747881
let bindir = sysroot.join("bin");
748882
t!(fs::create_dir_all(&bindir));

src/bootstrap/dist.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,15 @@ impl Step for Rustc {
434434
}
435435
}
436436

437+
// Copy over the codegen backends
438+
let backends_src = builder.sysroot_libdir(compiler, host)
439+
.join("codegen-backends");
440+
let backends_dst = image.join("lib/rustlib")
441+
.join(&*host)
442+
.join("lib/codegen-backends");
443+
t!(fs::create_dir_all(&backends_dst));
444+
cp_r(&backends_src, &backends_dst);
445+
437446
// Man pages
438447
t!(fs::create_dir_all(image.join("share/man/man1")));
439448
let man_src = build.src.join("src/doc/man");
@@ -581,7 +590,9 @@ impl Step for Std {
581590
t!(fs::create_dir_all(&dst));
582591
let mut src = builder.sysroot_libdir(compiler, target).to_path_buf();
583592
src.pop(); // Remove the trailing /lib folder from the sysroot_libdir
584-
cp_r(&src, &dst);
593+
cp_filtered(&src, &dst, &|path| {
594+
path.file_name().and_then(|s| s.to_str()) != Some("codegen-backends")
595+
});
585596

586597
let mut cmd = rust_installer(builder);
587598
cmd.arg("generate")

src/bootstrap/doc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ impl Step for Rustc {
617617
t!(symlink_dir_force(&my_out, &out_dir));
618618

619619
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc");
620-
compile::rustc_cargo(build, target, &mut cargo);
620+
compile::rustc_cargo(build, &mut cargo);
621621

622622
if build.config.compiler_docs {
623623
// src/rustc/Cargo.toml contains a bin crate called rustc which

src/bootstrap/lib.rs

-3
Original file line numberDiff line numberDiff line change
@@ -432,9 +432,6 @@ impl Build {
432432
if self.config.use_jemalloc {
433433
features.push_str(" jemalloc");
434434
}
435-
if self.config.llvm_enabled {
436-
features.push_str(" llvm");
437-
}
438435
features
439436
}
440437

0 commit comments

Comments
 (0)