Skip to content

Commit

Permalink
Merge #9235
Browse files Browse the repository at this point in the history
9235: Do not unconditionally succeed RUSTC_WRAPPER when run by build scripts r=Undin a=vlad20012

Fixes #9198, fixes #9227.

Based on rust-lang/rust-analyzer#13010 and discussion in rust-lang/rust-analyzer#12973.

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.

changelog: Fix broken `anyhow` compilation when `org.rust.cargo.evaluate.build.scripts` [experimental feature](https://plugins.jetbrains.com/plugin/8182-rust/docs/rust-faq.html#experimental-features) is enabled

Co-authored-by: vlad20012 <beskvlad@gmail.com>
  • Loading branch information
bors[bot] and vlad20012 committed Aug 30, 2022
2 parents 94dce5a + f540fe2 commit bc9f993
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 2 deletions.
10 changes: 8 additions & 2 deletions native-helper/src/rustc_wrapper.rs
@@ -1,13 +1,19 @@
use std::ffi::OsString;
use std::process::{Command, Stdio};
use std::io;
use std::process::{Command, Stdio};

pub struct ExitCode(pub Option<i32>);

pub fn run_rustc_skipping_cargo_checking(
rustc_executable: OsString,
args: Vec<OsString>,
) -> io::Result<ExitCode> {
// `CARGO_CFG_TARGET_ARCH` is only set by cargo when executing build scripts
// We don't want to exit out checks unconditionally with success if a build
// script tries to invoke checks themselves
// See https://github.com/rust-lang/rust-analyzer/issues/12973 for context
let is_invoked_by_build_script = std::env::var_os("CARGO_CFG_TARGET_ARCH").is_some();

let is_cargo_check = args.iter().any(|arg| {
let arg = arg.to_string_lossy();
// `cargo check` invokes `rustc` with `--emit=metadata` argument.
Expand All @@ -20,7 +26,7 @@ pub fn run_rustc_skipping_cargo_checking(
// The default output filename is CRATE_NAME.rmeta.
arg.starts_with("--emit=") && arg.contains("metadata") && !arg.contains("link")
});
if is_cargo_check {
if !is_invoked_by_build_script && is_cargo_check {
return Ok(ExitCode(Some(0)));
}
run_rustc(rustc_executable, args)
Expand Down
Expand Up @@ -972,6 +972,91 @@ class CargoGeneratedItemsResolveTest : RunConfigurationTestBase() {
}.checkReferenceIsResolved<RsPath>("src/main.rs")
}

fun `test rustc invoked from a build script is not always succeed during sync`() {
buildProject {
toml("Cargo.toml", """
[package]
name = "intellij-rust-test"
version = "0.1.0"
authors = []
""")
rust("build.rs", """
use std::env;
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process::{Command, ExitStatus, Stdio};
use std::str;
const PROBE: &str = r#"
pub fn foo() { There is a syntax error here. }
"#;
fn main() {
match compile_probe() {
Some(status) if status.success() => panic!("The probe must not succeed"),
None => panic!("Unknown failure"),
_ => {}
}
let out_dir = env::var("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("hello.rs");
let mut f = File::create(&dest_path).unwrap();
f.write_all(b"
pub fn message() -> &'static str {
\"Hello, World!\"
}",
).unwrap();
}
fn compile_probe() -> Option<ExitStatus> {
let rustc = env::var_os("RUSTC")?;
let out_dir = env::var_os("OUT_DIR")?;
let probefile = Path::new(&out_dir).join("probe.rs");
fs::write(&probefile, PROBE).ok()?;
// Make sure to pick up Cargo rustc configuration.
let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER") {
let mut cmd = Command::new(wrapper);
// The wrapper's first argument is supposed to be the path to rustc.
cmd.arg(rustc);
cmd
} else {
Command::new(rustc)
};
cmd.stderr(Stdio::null())
.arg("--crate-name=probe")
.arg("--crate-type=lib")
.arg("--emit=metadata")
.arg("--out-dir")
.arg(out_dir)
.arg(probefile);
if let Some(target) = env::var_os("TARGET") {
cmd.arg("--target").arg(target);
}
// If Cargo wants to set RUSTFLAGS, use that.
if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") {
if !rustflags.is_empty() {
for arg in rustflags.split('\x1f') {
cmd.arg(arg);
}
}
}
cmd.status().ok()
}
""")
dir("src") {
rust("main.rs", MAIN_RS)
}
}.checkReferenceIsResolved<RsPath>("src/main.rs")
}

companion object {
@Language("Rust")
private const val MAIN_RS = """
Expand Down

0 comments on commit bc9f993

Please sign in to comment.