Skip to content

Commit

Permalink
Wrapper enhancements
Browse files Browse the repository at this point in the history
* New-type the possibly-wrapped `rustc` commands.
* Use wrappers when reading the version -- fixes #58.
* Test with a wrapper script that reads input -- fixes #61.
  • Loading branch information
cuviper committed May 2, 2024
1 parent c10bc17 commit 0656eb0
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 48 deletions.
52 changes: 8 additions & 44 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,17 @@ use std::ffi::OsString;
use std::fs;
use std::io::{stderr, Write};
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::process::Stdio;
#[allow(deprecated)]
use std::sync::atomic::ATOMIC_USIZE_INIT;
use std::sync::atomic::{AtomicUsize, Ordering};

mod error;
pub use error::Error;

mod rustc;
use rustc::Rustc;

mod version;
use version::Version;

Expand All @@ -82,9 +85,7 @@ mod tests;
#[derive(Clone, Debug)]
pub struct AutoCfg {
out_dir: PathBuf,
rustc: PathBuf,
rustc_wrapper: Option<PathBuf>,
rustc_workspace_wrapper: Option<PathBuf>,
rustc: Rustc,
rustc_version: Version,
target: Option<OsString>,
no_std: bool,
Expand Down Expand Up @@ -155,9 +156,8 @@ impl AutoCfg {
/// - `dir` is not a writable directory.
///
pub fn with_dir<T: Into<PathBuf>>(dir: T) -> Result<Self, Error> {
let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
let rustc: PathBuf = rustc.into();
let rustc_version = try!(Version::from_rustc(&rustc));
let rustc = Rustc::new();
let rustc_version = try!(rustc.version());

let target = env::var_os("TARGET");

Expand All @@ -170,8 +170,6 @@ impl AutoCfg {

let mut ac = AutoCfg {
rustflags: rustflags(&target, &dir),
rustc_wrapper: get_rustc_wrapper(false),
rustc_workspace_wrapper: get_rustc_wrapper(true),
out_dir: dir,
rustc: rustc,
rustc_version: rustc_version,
Expand Down Expand Up @@ -239,17 +237,7 @@ impl AutoCfg {

let id = ID.fetch_add(1, Ordering::Relaxed);

// Build the command with possible wrappers.
let mut rustc = self
.rustc_wrapper
.iter()
.chain(self.rustc_workspace_wrapper.iter())
.chain(Some(&self.rustc));
let mut command = Command::new(rustc.next().unwrap());
for arg in rustc {
command.arg(arg);
}

let mut command = self.rustc.command();
command
.arg("--crate-name")
.arg(format!("probe{}", id))
Expand Down Expand Up @@ -493,27 +481,3 @@ fn rustflags(target: &Option<OsString>, dir: &Path) -> Vec<String> {

Vec::new()
}

fn get_rustc_wrapper(workspace: bool) -> Option<PathBuf> {
// We didn't really know whether the workspace wrapper is applicable until Cargo started
// deliberately setting or unsetting it in rust-lang/cargo#9601. We'll use the encoded
// rustflags as a proxy for that change for now, but we could instead check version 1.55.
if workspace && env::var_os("CARGO_ENCODED_RUSTFLAGS").is_none() {
return None;
}

let name = if workspace {
"RUSTC_WORKSPACE_WRAPPER"
} else {
"RUSTC_WRAPPER"
};

if let Some(wrapper) = env::var_os(name) {
// NB: `OsStr` didn't get `len` or `is_empty` until 1.9.
if wrapper != OsString::new() {
return Some(wrapper.into());
}
}

None
}
89 changes: 89 additions & 0 deletions src/rustc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use std::env;
use std::ffi::OsString;
use std::path::PathBuf;
use std::process::Command;

use super::error::Error;
use super::version::Version;

#[derive(Clone, Debug)]
pub struct Rustc {
rustc: PathBuf,
rustc_wrapper: Option<PathBuf>,
rustc_workspace_wrapper: Option<PathBuf>,
}

impl Rustc {
pub fn new() -> Self {
Rustc {
rustc: env::var_os("RUSTC")
.unwrap_or_else(|| "rustc".into())
.into(),
rustc_wrapper: get_rustc_wrapper(false),
rustc_workspace_wrapper: get_rustc_wrapper(true),
}
}

/// Build the command with possible wrappers.
pub fn command(&self) -> Command {
let mut rustc = self
.rustc_wrapper
.iter()
.chain(self.rustc_workspace_wrapper.iter())
.chain(Some(&self.rustc));
let mut command = Command::new(rustc.next().unwrap());
for arg in rustc {
command.arg(arg);
}
command
}

/// Try to get the `rustc` version.
pub fn version(&self) -> Result<Version, Error> {
// Some wrappers like clippy-driver don't pass through version commands,
// so we try to fall back to combinations without each wrapper.
macro_rules! try_version {
($command:expr) => {
if let Ok(value) = Version::from_command($command) {
return Ok(value);
}
};
}

let rustc = &self.rustc;
if let Some(ref rw) = self.rustc_wrapper {
if let Some(ref rww) = self.rustc_workspace_wrapper {
try_version!(Command::new(rw).args(&[rww, rustc]));
}
try_version!(Command::new(rw).arg(rustc));
}
if let Some(ref rww) = self.rustc_workspace_wrapper {
try_version!(Command::new(rww).arg(rustc));
}
Version::from_command(&mut Command::new(rustc))
}
}

fn get_rustc_wrapper(workspace: bool) -> Option<PathBuf> {
// We didn't really know whether the workspace wrapper is applicable until Cargo started
// deliberately setting or unsetting it in rust-lang/cargo#9601. We'll use the encoded
// rustflags as a proxy for that change for now, but we could instead check version 1.55.
if workspace && env::var_os("CARGO_ENCODED_RUSTFLAGS").is_none() {
return None;
}

let name = if workspace {
"RUSTC_WORKSPACE_WRAPPER"
} else {
"RUSTC_WRAPPER"
};

if let Some(wrapper) = env::var_os(name) {
// NB: `OsStr` didn't get `len` or `is_empty` until 1.9.
if wrapper != OsString::new() {
return Some(wrapper.into());
}
}

None
}
5 changes: 2 additions & 3 deletions src/version.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::path::Path;
use std::process::Command;
use std::str;

Expand All @@ -22,9 +21,9 @@ impl Version {
}
}

pub fn from_rustc(rustc: &Path) -> Result<Self, Error> {
pub fn from_command(command: &mut Command) -> Result<Self, Error> {
// Get rustc's verbose version
let output = try!(Command::new(rustc)
let output = try!(command
.args(&["--version", "--verbose"])
.output()
.map_err(error::from_io));
Expand Down
12 changes: 12 additions & 0 deletions tests/wrap_ignored
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash

for arg in "$@"; do
case "$arg" in
# Add our own version so we can check that the wrapper is used for that.
"--version") echo "release: 12345.6789.0" ;;
# Read all input so the writer doesn't get EPIPE when we exit.
"-") read -d "" PROBE ;;
esac
done

exit 0
7 changes: 6 additions & 1 deletion tests/wrappers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,18 @@ fn test_wrappers() {
assert!(ac.probe_type("usize"));
assert!(!ac.probe_type("mesize"));
}
// Either way, we should have found the inner rustc version.
assert!(ac.probe_rustc_version(1, 0));
}
}

// Finally, make sure that `RUSTC_WRAPPER` is applied outermost
// by using something that doesn't pass through at all.
env::set_var("RUSTC_WRAPPER", "/bin/true");
env::set_var("RUSTC_WRAPPER", "./tests/wrap_ignored");
env::set_var("RUSTC_WORKSPACE_WRAPPER", "/bin/false");
let ac = autocfg::AutoCfg::new().unwrap();
assert!(ac.probe_type("mesize")); // anything goes!

// Make sure we also got the version from that wrapper.
assert!(ac.probe_rustc_version(12345, 6789));
}

0 comments on commit 0656eb0

Please sign in to comment.