diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 70e4a69a07d..ca86aeb8100 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -109,6 +109,12 @@ fn main() { cmd.arg("-Zexternal-macro-backtrace"); + // Link crates to the proc macro crate for the target, but use a host proc macro crate + // to actually run the macros + if env::var_os("RUST_DUAL_PROC_MACROS").is_some() { + cmd.arg("-Zdual-proc-macros"); + } + // When we build Rust dylibs they're all intended for intermediate // usage, so make sure we pass the -Cprefer-dynamic flag instead of // linking all deps statically into the dylib. @@ -258,13 +264,6 @@ fn main() { } } - // Force all crates compiled by this compiler to (a) be unstable and (b) - // allow the `rustc_private` feature to link to other unstable crates - // also in the sysroot. - if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() { - cmd.arg("-Z").arg("force-unstable-if-unmarked"); - } - if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") { cmd.arg("--remap-path-prefix").arg(&map); } @@ -284,6 +283,14 @@ fn main() { } } + // Force all crates compiled by this compiler to (a) be unstable and (b) + // allow the `rustc_private` feature to link to other unstable crates + // also in the sysroot. We also do this for host crates, since those + // may be proc macros, in which case we might ship them. + if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() && (stage != "0" || target.is_some()) { + cmd.arg("-Z").arg("force-unstable-if-unmarked"); + } + if env::var_os("RUSTC_PARALLEL_COMPILER").is_some() { cmd.arg("--cfg").arg("parallel_compiler"); } diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 7e6c0a9f52a..eb1a2a59fa3 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -812,6 +812,17 @@ impl<'a> Builder<'a> { cargo.env("RUST_CHECK", "1"); } + match mode { + Mode::Std | Mode::Test | Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolTest=> {}, + Mode::Rustc | Mode::Codegen | Mode::ToolRustc => { + // Build proc macros both for the host and the target + if target != compiler.host && cmd != "check" { + cargo.arg("-Zdual-proc-macros"); + cargo.env("RUST_DUAL_PROC_MACROS", "1"); + } + }, + } + cargo.arg("-j").arg(self.jobs().to_string()); // Remove make-related flags to ensure Cargo can correctly set things up cargo.env_remove("MAKEFLAGS"); diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 20370372082..a30b465698e 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -42,7 +42,8 @@ impl Step for Std { true); let libdir = builder.sysroot_libdir(compiler, target); - add_to_sysroot(&builder, &libdir, &libstd_stamp(builder, compiler, target)); + let hostdir = builder.sysroot_libdir(compiler, compiler.host); + add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target)); } } @@ -88,7 +89,8 @@ impl Step for Rustc { true); let libdir = builder.sysroot_libdir(compiler, target); - add_to_sysroot(&builder, &libdir, &librustc_stamp(builder, compiler, target)); + let hostdir = builder.sysroot_libdir(compiler, compiler.host); + add_to_sysroot(&builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target)); } } @@ -175,7 +177,8 @@ impl Step for Test { true); let libdir = builder.sysroot_libdir(compiler, target); - add_to_sysroot(builder, &libdir, &libtest_stamp(builder, compiler, target)); + let hostdir = builder.sysroot_libdir(compiler, compiler.host); + add_to_sysroot(builder, &libdir, &hostdir, &libtest_stamp(builder, compiler, target)); } } @@ -222,7 +225,8 @@ impl Step for Rustdoc { true); let libdir = builder.sysroot_libdir(compiler, target); - add_to_sysroot(&builder, &libdir, &rustdoc_stamp(builder, compiler, target)); + let hostdir = builder.sysroot_libdir(compiler, compiler.host); + add_to_sysroot(&builder, &libdir, &hostdir, &rustdoc_stamp(builder, compiler, target)); builder.cargo(compiler, Mode::ToolRustc, target, "clean"); } } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 249a1831890..9498dbb5952 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -224,7 +224,8 @@ impl Step for StdLink { target_compiler.host, target)); let libdir = builder.sysroot_libdir(target_compiler, target); - add_to_sysroot(builder, &libdir, &libstd_stamp(builder, compiler, target)); + let hostdir = builder.sysroot_libdir(target_compiler, compiler.host); + add_to_sysroot(builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target)); if builder.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" { // The sanitizers are only built in stage1 or above, so the dylibs will @@ -431,8 +432,12 @@ impl Step for TestLink { &compiler.host, target_compiler.host, target)); - add_to_sysroot(builder, &builder.sysroot_libdir(target_compiler, target), - &libtest_stamp(builder, compiler, target)); + add_to_sysroot( + builder, + &builder.sysroot_libdir(target_compiler, target), + &builder.sysroot_libdir(target_compiler, compiler.host), + &libtest_stamp(builder, compiler, target) + ); builder.cargo(target_compiler, Mode::ToolTest, target, "clean"); } @@ -496,8 +501,8 @@ impl Step for Rustc { return; } - // Ensure that build scripts have a std to link against. - builder.ensure(Std { + // Ensure that build scripts and proc macros have a std / libproc_macro to link against. + builder.ensure(Test { compiler: builder.compiler(self.compiler.stage, builder.config.build), target: builder.config.build, }); @@ -592,8 +597,12 @@ impl Step for RustcLink { &compiler.host, target_compiler.host, target)); - add_to_sysroot(builder, &builder.sysroot_libdir(target_compiler, target), - &librustc_stamp(builder, compiler, target)); + add_to_sysroot( + builder, + &builder.sysroot_libdir(target_compiler, target), + &builder.sysroot_libdir(target_compiler, compiler.host), + &librustc_stamp(builder, compiler, target) + ); builder.cargo(target_compiler, Mode::ToolRustc, target, "clean"); } } @@ -1015,10 +1024,20 @@ impl Step for Assemble { /// /// For a particular stage this will link the file listed in `stamp` into the /// `sysroot_dst` provided. -pub fn add_to_sysroot(builder: &Builder<'_>, sysroot_dst: &Path, stamp: &Path) { +pub fn add_to_sysroot( + builder: &Builder<'_>, + sysroot_dst: &Path, + sysroot_host_dst: &Path, + stamp: &Path +) { t!(fs::create_dir_all(&sysroot_dst)); - for path in builder.read_stamp_file(stamp) { - builder.copy(&path, &sysroot_dst.join(path.file_name().unwrap())); + t!(fs::create_dir_all(&sysroot_host_dst)); + for (path, host) in builder.read_stamp_file(stamp) { + if host { + builder.copy(&path, &sysroot_host_dst.join(path.file_name().unwrap())); + } else { + builder.copy(&path, &sysroot_dst.join(path.file_name().unwrap())); + } } } @@ -1047,8 +1066,14 @@ pub fn run_cargo(builder: &Builder<'_>, let mut deps = Vec::new(); let mut toplevel = Vec::new(); let ok = stream_cargo(builder, cargo, &mut |msg| { - let filenames = match msg { - CargoMessage::CompilerArtifact { filenames, .. } => filenames, + let (filenames, crate_types) = match msg { + CargoMessage::CompilerArtifact { + filenames, + target: CargoTarget { + crate_types, + }, + .. + } => (filenames, crate_types), _ => return, }; for filename in filenames { @@ -1063,15 +1088,19 @@ pub fn run_cargo(builder: &Builder<'_>, let filename = Path::new(&*filename); // If this was an output file in the "host dir" we don't actually - // worry about it, it's not relevant for us. + // worry about it, it's not relevant for us if filename.starts_with(&host_root_dir) { + // Unless it's a proc macro used in the compiler + if crate_types.iter().any(|t| t == "proc-macro") { + deps.push((filename.to_path_buf(), true)); + } continue; } // If this was output in the `deps` dir then this is a precise file // name (hash included) so we start tracking it. if filename.starts_with(&target_deps_dir) { - deps.push(filename.to_path_buf()); + deps.push((filename.to_path_buf(), false)); continue; } @@ -1124,10 +1153,10 @@ pub fn run_cargo(builder: &Builder<'_>, let candidate = format!("{}.lib", path_to_add); let candidate = PathBuf::from(candidate); if candidate.exists() { - deps.push(candidate); + deps.push((candidate, false)); } } - deps.push(path_to_add.into()); + deps.push((path_to_add.into(), false)); } // Now we want to update the contents of the stamp file, if necessary. First @@ -1140,12 +1169,13 @@ pub fn run_cargo(builder: &Builder<'_>, let mut new_contents = Vec::new(); let mut max = None; let mut max_path = None; - for dep in deps.iter() { + for (dep, proc_macro) in deps.iter() { let mtime = mtime(dep); if Some(mtime) > max { max = Some(mtime); max_path = Some(dep.clone()); } + new_contents.extend(if *proc_macro { b"h" } else { b"t" }); new_contents.extend(dep.to_str().unwrap().as_bytes()); new_contents.extend(b"\0"); } @@ -1157,7 +1187,7 @@ pub fn run_cargo(builder: &Builder<'_>, if contents_equal && max <= stamp_mtime { builder.verbose(&format!("not updating {:?}; contents equal and {:?} <= {:?}", stamp, max, stamp_mtime)); - return deps + return deps.into_iter().map(|(d, _)| d).collect() } if max > stamp_mtime { builder.verbose(&format!("updating {:?} as {:?} changed", stamp, max_path)); @@ -1165,7 +1195,7 @@ pub fn run_cargo(builder: &Builder<'_>, builder.verbose(&format!("updating {:?} as deps changed", stamp)); } t!(fs::write(&stamp, &new_contents)); - deps + deps.into_iter().map(|(d, _)| d).collect() } pub fn stream_cargo( @@ -1211,6 +1241,11 @@ pub fn stream_cargo( status.success() } +#[derive(Deserialize)] +pub struct CargoTarget<'a> { + crate_types: Vec>, +} + #[derive(Deserialize)] #[serde(tag = "reason", rename_all = "kebab-case")] pub enum CargoMessage<'a> { @@ -1218,6 +1253,7 @@ pub enum CargoMessage<'a> { package_id: Cow<'a, str>, features: Vec>, filenames: Vec>, + target: CargoTarget<'a>, }, BuildScriptExecuted { package_id: Cow<'a, str>, diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 84e2c5aab54..9317a40545e 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1129,7 +1129,7 @@ impl Build { ret } - fn read_stamp_file(&self, stamp: &Path) -> Vec { + fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, bool)> { if self.config.dry_run { return Vec::new(); } @@ -1142,8 +1142,9 @@ impl Build { if part.is_empty() { continue } - let path = PathBuf::from(t!(str::from_utf8(part))); - paths.push(path); + let host = part[0] as char == 'h'; + let path = PathBuf::from(t!(str::from_utf8(&part[1..]))); + paths.push((path, host)); } paths } diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 51412f79c3d..6e37bf33452 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -213,7 +213,7 @@ impl Step for Cargo { }); let mut cargo = tool::prepare_tool_cargo(builder, compiler, - Mode::ToolRustc, + Mode::ToolStd, self.host, "test", "src/tools/cargo", diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index fc1a17d5466..b12ccc4f39d 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -91,7 +91,8 @@ impl Step for ToolBuild { compile::CargoMessage::CompilerArtifact { package_id, features, - filenames + filenames, + target: _, } => { (package_id, features, filenames) } @@ -513,7 +514,7 @@ impl Step for Cargo { compiler: self.compiler, target: self.target, tool: "cargo", - mode: Mode::ToolRustc, + mode: Mode::ToolStd, path: "src/tools/cargo", is_optional_tool: false, source_type: SourceType::Submodule,