Skip to content

Commit f540fe2

Browse files
committed
Do not unconditionally succeed RUSTC_WRAPPER when run by build scripts
intellij-rust-native-helper in `RUSTC_WRAPPER` role unconditionally succeeds `cargo check` invocations tripping up build scripts using `cargo check` to probe for successful compilations. To prevent this from happening the `RUSTC_WRAPPER` now checks if it's run from a build script by looking for the `CARGO_CFG_TARGET_ARCH` env var that cargo sets only when running build scripts.
1 parent ebcedfa commit f540fe2

File tree

2 files changed

+93
-2
lines changed

2 files changed

+93
-2
lines changed

native-helper/src/rustc_wrapper.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
use std::ffi::OsString;
2-
use std::process::{Command, Stdio};
32
use std::io;
3+
use std::process::{Command, Stdio};
44

55
pub struct ExitCode(pub Option<i32>);
66

77
pub fn run_rustc_skipping_cargo_checking(
88
rustc_executable: OsString,
99
args: Vec<OsString>,
1010
) -> io::Result<ExitCode> {
11+
// `CARGO_CFG_TARGET_ARCH` is only set by cargo when executing build scripts
12+
// We don't want to exit out checks unconditionally with success if a build
13+
// script tries to invoke checks themselves
14+
// See https://github.com/rust-lang/rust-analyzer/issues/12973 for context
15+
let is_invoked_by_build_script = std::env::var_os("CARGO_CFG_TARGET_ARCH").is_some();
16+
1117
let is_cargo_check = args.iter().any(|arg| {
1218
let arg = arg.to_string_lossy();
1319
// `cargo check` invokes `rustc` with `--emit=metadata` argument.
@@ -20,7 +26,7 @@ pub fn run_rustc_skipping_cargo_checking(
2026
// The default output filename is CRATE_NAME.rmeta.
2127
arg.starts_with("--emit=") && arg.contains("metadata") && !arg.contains("link")
2228
});
23-
if is_cargo_check {
29+
if !is_invoked_by_build_script && is_cargo_check {
2430
return Ok(ExitCode(Some(0)));
2531
}
2632
run_rustc(rustc_executable, args)

src/test/kotlin/org/rustSlowTests/lang/resolve/CargoGeneratedItemsResolveTest.kt

+85
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,91 @@ class CargoGeneratedItemsResolveTest : RunConfigurationTestBase() {
972972
}.checkReferenceIsResolved<RsPath>("src/main.rs")
973973
}
974974

975+
fun `test rustc invoked from a build script is not always succeed during sync`() {
976+
buildProject {
977+
toml("Cargo.toml", """
978+
[package]
979+
name = "intellij-rust-test"
980+
version = "0.1.0"
981+
authors = []
982+
""")
983+
rust("build.rs", """
984+
use std::env;
985+
use std::fs;
986+
use std::fs::File;
987+
use std::io::Write;
988+
use std::path::Path;
989+
use std::process::{Command, ExitStatus, Stdio};
990+
use std::str;
991+
992+
const PROBE: &str = r#"
993+
pub fn foo() { There is a syntax error here. }
994+
"#;
995+
996+
fn main() {
997+
match compile_probe() {
998+
Some(status) if status.success() => panic!("The probe must not succeed"),
999+
None => panic!("Unknown failure"),
1000+
_ => {}
1001+
}
1002+
1003+
let out_dir = env::var("OUT_DIR").unwrap();
1004+
let dest_path = Path::new(&out_dir).join("hello.rs");
1005+
let mut f = File::create(&dest_path).unwrap();
1006+
1007+
f.write_all(b"
1008+
pub fn message() -> &'static str {
1009+
\"Hello, World!\"
1010+
}",
1011+
).unwrap();
1012+
}
1013+
1014+
fn compile_probe() -> Option<ExitStatus> {
1015+
let rustc = env::var_os("RUSTC")?;
1016+
let out_dir = env::var_os("OUT_DIR")?;
1017+
let probefile = Path::new(&out_dir).join("probe.rs");
1018+
fs::write(&probefile, PROBE).ok()?;
1019+
1020+
// Make sure to pick up Cargo rustc configuration.
1021+
let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER") {
1022+
let mut cmd = Command::new(wrapper);
1023+
// The wrapper's first argument is supposed to be the path to rustc.
1024+
cmd.arg(rustc);
1025+
cmd
1026+
} else {
1027+
Command::new(rustc)
1028+
};
1029+
1030+
cmd.stderr(Stdio::null())
1031+
.arg("--crate-name=probe")
1032+
.arg("--crate-type=lib")
1033+
.arg("--emit=metadata")
1034+
.arg("--out-dir")
1035+
.arg(out_dir)
1036+
.arg(probefile);
1037+
1038+
if let Some(target) = env::var_os("TARGET") {
1039+
cmd.arg("--target").arg(target);
1040+
}
1041+
1042+
// If Cargo wants to set RUSTFLAGS, use that.
1043+
if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") {
1044+
if !rustflags.is_empty() {
1045+
for arg in rustflags.split('\x1f') {
1046+
cmd.arg(arg);
1047+
}
1048+
}
1049+
}
1050+
1051+
cmd.status().ok()
1052+
}
1053+
""")
1054+
dir("src") {
1055+
rust("main.rs", MAIN_RS)
1056+
}
1057+
}.checkReferenceIsResolved<RsPath>("src/main.rs")
1058+
}
1059+
9751060
companion object {
9761061
@Language("Rust")
9771062
private const val MAIN_RS = """

0 commit comments

Comments
 (0)