Skip to content

Commit fb0130c

Browse files
committed
Auto merge of #9365 - jyn514:rustc-bootstrap-crate-name, r=ehuss
Don't give a hard error when the end-user specifies RUSTC_BOOTSTRAP=crate_name Fixes #9362. The whole point of rust-lang/rust#77802 was to allow specifying this granularly, giving a hard error defeats the point. I didn't know how to check what targets were reverse-dependencies of build.rs, so I just unconditionally use the library name (and give a hard error for anything else, even if it's the name of one of the binaries). End-users can still opt-in with RUSTC_BOOTSTRAP=1, and no public binaries use RUSTC_BOOTSTRAP=1, so I don't think this a big deal in practice. <details><summary>Script to verify all crates using RUSTC_BOOTSTRAP=1 have a library</summary> ```sh curl https://pastebin.com/raw/fGQ97xP6 | cut -d / -f1 | grep -v shnatsel | grep -v cargo- | sed 's#-\([0-9]\)#/\1#' | xargs -i curl -s -I -L "https://docs.rs/{}/" -w "%{http_code}\n" -o/dev/null ``` It should output 20 200s in a row. </details> r? `@ehuss` cc `@mark-simulacrum` I don't know what cargo's policy is for backports, but this should be backported to 1.52.
2 parents a18936b + 5a71496 commit fb0130c

File tree

3 files changed

+87
-23
lines changed

3 files changed

+87
-23
lines changed

src/cargo/core/compiler/custom_build.rs

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use crate::core::compiler::context::Metadata;
44
use crate::core::compiler::job_queue::JobState;
55
use crate::core::{profiles::ProfileRoot, PackageId};
66
use crate::util::errors::CargoResult;
7-
use crate::util::interning::InternedString;
87
use crate::util::machine_message::{self, Message};
98
use crate::util::{internal, profile};
109
use anyhow::Context as _;
@@ -270,7 +269,7 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> {
270269
}
271270
})
272271
.collect::<Vec<_>>();
273-
let pkg_name = unit.pkg.name();
272+
let library_name = unit.pkg.library().map(|t| t.crate_name());
274273
let pkg_descr = unit.pkg.to_string();
275274
let build_script_outputs = Arc::clone(&cx.build_script_outputs);
276275
let id = unit.pkg.package_id();
@@ -280,7 +279,7 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> {
280279
let host_target_root = cx.files().host_dest().to_path_buf();
281280
let all = (
282281
id,
283-
pkg_name,
282+
library_name.clone(),
284283
pkg_descr.clone(),
285284
Arc::clone(&build_script_outputs),
286285
output_file.clone(),
@@ -400,7 +399,7 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> {
400399
paths::write(&root_output_file, paths::path2bytes(&script_out_dir)?)?;
401400
let parsed_output = BuildOutput::parse(
402401
&output.stdout,
403-
pkg_name,
402+
library_name,
404403
&pkg_descr,
405404
&script_out_dir,
406405
&script_out_dir,
@@ -422,12 +421,12 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> {
422421
// itself to run when we actually end up just discarding what we calculated
423422
// above.
424423
let fresh = Work::new(move |state| {
425-
let (id, pkg_name, pkg_descr, build_script_outputs, output_file, script_out_dir) = all;
424+
let (id, library_name, pkg_descr, build_script_outputs, output_file, script_out_dir) = all;
426425
let output = match prev_output {
427426
Some(output) => output,
428427
None => BuildOutput::parse_file(
429428
&output_file,
430-
pkg_name,
429+
library_name,
431430
&pkg_descr,
432431
&prev_script_out_dir,
433432
&script_out_dir,
@@ -479,7 +478,7 @@ fn insert_warnings_in_build_outputs(
479478
impl BuildOutput {
480479
pub fn parse_file(
481480
path: &Path,
482-
pkg_name: InternedString,
481+
library_name: Option<String>,
483482
pkg_descr: &str,
484483
script_out_dir_when_generated: &Path,
485484
script_out_dir: &Path,
@@ -489,7 +488,7 @@ impl BuildOutput {
489488
let contents = paths::read_bytes(path)?;
490489
BuildOutput::parse(
491490
&contents,
492-
pkg_name,
491+
library_name,
493492
pkg_descr,
494493
script_out_dir_when_generated,
495494
script_out_dir,
@@ -499,10 +498,12 @@ impl BuildOutput {
499498
}
500499

501500
// Parses the output of a script.
502-
// The `pkg_name` is used for error messages.
501+
// The `pkg_descr` is used for error messages.
502+
// The `library_name` is used for determining if RUSTC_BOOTSTRAP should be allowed.
503503
pub fn parse(
504504
input: &[u8],
505-
pkg_name: InternedString,
505+
// Takes String instead of InternedString so passing `unit.pkg.name()` will give a compile error.
506+
library_name: Option<String>,
506507
pkg_descr: &str,
507508
script_out_dir_when_generated: &Path,
508509
script_out_dir: &Path,
@@ -589,7 +590,23 @@ impl BuildOutput {
589590
// to set RUSTC_BOOTSTRAP.
590591
// If this is a nightly build, setting RUSTC_BOOTSTRAP wouldn't affect the
591592
// behavior, so still only give a warning.
592-
if nightly_features_allowed {
593+
// NOTE: cargo only allows nightly features on RUSTC_BOOTSTRAP=1, but we
594+
// want setting any value of RUSTC_BOOTSTRAP to downgrade this to a warning
595+
// (so that `RUSTC_BOOTSTRAP=library_name` will work)
596+
let rustc_bootstrap_allows = |name: Option<&str>| {
597+
let name = match name {
598+
// as of 2021, no binaries on crates.io use RUSTC_BOOTSTRAP, so
599+
// fine-grained opt-outs aren't needed. end-users can always use
600+
// RUSTC_BOOTSTRAP=1 from the top-level if it's really a problem.
601+
None => return false,
602+
Some(n) => n,
603+
};
604+
std::env::var("RUSTC_BOOTSTRAP")
605+
.map_or(false, |var| var.split(',').any(|s| s == name))
606+
};
607+
if nightly_features_allowed
608+
|| rustc_bootstrap_allows(library_name.as_deref())
609+
{
593610
warnings.push(format!("Cannot set `RUSTC_BOOTSTRAP={}` from {}.\n\
594611
note: Crates cannot set `RUSTC_BOOTSTRAP` themselves, as doing so would subvert the stability guarantees of Rust for your project.",
595612
val, whence
@@ -602,7 +619,7 @@ impl BuildOutput {
602619
help: If you're sure you want to do this in your project, set the environment variable `RUSTC_BOOTSTRAP={}` before running cargo instead.",
603620
val,
604621
whence,
605-
pkg_name,
622+
library_name.as_deref().unwrap_or("1"),
606623
);
607624
}
608625
} else {
@@ -859,7 +876,7 @@ fn prev_build_output(cx: &mut Context<'_, '_>, unit: &Unit) -> (Option<BuildOutp
859876
(
860877
BuildOutput::parse_file(
861878
&output_file,
862-
unit.pkg.name(),
879+
unit.pkg.library().map(|t| t.crate_name()),
863880
&unit.pkg.to_string(),
864881
&prev_script_out_dir,
865882
&script_out_dir,

src/cargo/core/package.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ impl Package {
151151
pub fn targets(&self) -> &[Target] {
152152
self.manifest().targets()
153153
}
154+
/// Gets the library crate for this package, if it exists.
155+
pub fn library(&self) -> Option<&Target> {
156+
self.targets().iter().find(|t| t.is_lib())
157+
}
154158
/// Gets the current package version.
155159
pub fn version(&self) -> &Version {
156160
self.package_id().version()

tests/testsuite/build_script_env.rs

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Tests for build.rs rerun-if-env-changed and rustc-env
22
3+
use cargo_test_support::basic_manifest;
34
use cargo_test_support::project;
45
use cargo_test_support::sleep_ms;
56

@@ -109,24 +110,66 @@ fn rerun_if_env_or_file_changes() {
109110

110111
#[cargo_test]
111112
fn rustc_bootstrap() {
113+
let build_rs = r#"
114+
fn main() {
115+
println!("cargo:rustc-env=RUSTC_BOOTSTRAP=1");
116+
}
117+
"#;
112118
let p = project()
113-
.file("src/main.rs", "fn main() {}")
114-
.file(
115-
"build.rs",
116-
r#"
117-
fn main() {
118-
println!("cargo:rustc-env=RUSTC_BOOTSTRAP=1");
119-
}
120-
"#,
121-
)
119+
.file("Cargo.toml", &basic_manifest("has-dashes", "0.0.1"))
120+
.file("src/lib.rs", "#![feature(rustc_attrs)]")
121+
.file("build.rs", build_rs)
122122
.build();
123+
// RUSTC_BOOTSTRAP unset on stable should error
123124
p.cargo("build")
124125
.with_stderr_contains("error: Cannot set `RUSTC_BOOTSTRAP=1` [..]")
125-
.with_stderr_contains("help: [..] set the environment variable `RUSTC_BOOTSTRAP=foo` [..]")
126+
.with_stderr_contains(
127+
"help: [..] set the environment variable `RUSTC_BOOTSTRAP=has_dashes` [..]",
128+
)
126129
.with_status(101)
127130
.run();
131+
// nightly should warn whether or not RUSTC_BOOTSTRAP is set
128132
p.cargo("build")
129133
.masquerade_as_nightly_cargo()
134+
// NOTE: uses RUSTC_BOOTSTRAP so it will be propagated to rustc
135+
// (this matters when tests are being run with a beta or stable cargo)
136+
.env("RUSTC_BOOTSTRAP", "1")
130137
.with_stderr_contains("warning: Cannot set `RUSTC_BOOTSTRAP=1` [..]")
131138
.run();
139+
// RUSTC_BOOTSTRAP set to the name of the library should warn
140+
p.cargo("build")
141+
.env("RUSTC_BOOTSTRAP", "has_dashes")
142+
.with_stderr_contains("warning: Cannot set `RUSTC_BOOTSTRAP=1` [..]")
143+
.run();
144+
// RUSTC_BOOTSTRAP set to some random value should error
145+
p.cargo("build")
146+
.env("RUSTC_BOOTSTRAP", "bar")
147+
.with_stderr_contains("error: Cannot set `RUSTC_BOOTSTRAP=1` [..]")
148+
.with_stderr_contains(
149+
"help: [..] set the environment variable `RUSTC_BOOTSTRAP=has_dashes` [..]",
150+
)
151+
.with_status(101)
152+
.run();
153+
154+
// Tests for binaries instead of libraries
155+
let p = project()
156+
.file("Cargo.toml", &basic_manifest("foo", "0.0.1"))
157+
.file("src/main.rs", "#![feature(rustc_attrs)] fn main() {}")
158+
.file("build.rs", build_rs)
159+
.build();
160+
// nightly should warn when there's no library whether or not RUSTC_BOOTSTRAP is set
161+
p.cargo("build")
162+
.masquerade_as_nightly_cargo()
163+
// NOTE: uses RUSTC_BOOTSTRAP so it will be propagated to rustc
164+
// (this matters when tests are being run with a beta or stable cargo)
165+
.env("RUSTC_BOOTSTRAP", "1")
166+
.with_stderr_contains("warning: Cannot set `RUSTC_BOOTSTRAP=1` [..]")
167+
.run();
168+
// RUSTC_BOOTSTRAP conditionally set when there's no library should error (regardless of the value)
169+
p.cargo("build")
170+
.env("RUSTC_BOOTSTRAP", "foo")
171+
.with_stderr_contains("error: Cannot set `RUSTC_BOOTSTRAP=1` [..]")
172+
.with_stderr_contains("help: [..] set the environment variable `RUSTC_BOOTSTRAP=1` [..]")
173+
.with_status(101)
174+
.run();
132175
}

0 commit comments

Comments
 (0)