1use std::env;
2use std::ffi::OsString;
3use std::path::PathBuf;
4use std::process::Command;
5
6use super::error::Error;
7use super::version::Version;
8
9#[derive(Clone, Debug)]
10pub struct Rustc {
11 rustc: PathBuf,
12 rustc_wrapper: Option<PathBuf>,
13 rustc_workspace_wrapper: Option<PathBuf>,
14}
15
16impl Rustc {
17 pub fn new() -> Self {
18 Rustc {
19 rustc: env::var_os("RUSTC")
20 .unwrap_or_else(|| "rustc".into())
21 .into(),
22 rustc_wrapper: get_rustc_wrapper(false),
23 rustc_workspace_wrapper: get_rustc_wrapper(true),
24 }
25 }
26
27 /// Build the command with possible wrappers.
28 pub fn command(&self) -> Command {
29 let mut rustc = self
30 .rustc_wrapper
31 .iter()
32 .chain(self.rustc_workspace_wrapper.iter())
33 .chain(Some(&self.rustc));
34 let mut command = Command::new(rustc.next().unwrap());
35 for arg in rustc {
36 command.arg(arg);
37 }
38 command
39 }
40
41 /// Try to get the `rustc` version.
42 pub fn version(&self) -> Result<Version, Error> {
43 // Some wrappers like clippy-driver don't pass through version commands,
44 // so we try to fall back to combinations without each wrapper.
45 macro_rules! try_version {
46 ($command:expr) => {
47 if let Ok(value) = Version::from_command($command) {
48 return Ok(value);
49 }
50 };
51 }
52
53 let rustc = &self.rustc;
54 if let Some(ref rw) = self.rustc_wrapper {
55 if let Some(ref rww) = self.rustc_workspace_wrapper {
56 try_version!(Command::new(rw).args(&[rww, rustc]));
57 }
58 try_version!(Command::new(rw).arg(rustc));
59 }
60 if let Some(ref rww) = self.rustc_workspace_wrapper {
61 try_version!(Command::new(rww).arg(rustc));
62 }
63 Version::from_command(&mut Command::new(rustc))
64 }
65}
66
67fn get_rustc_wrapper(workspace: bool) -> Option<PathBuf> {
68 // We didn't really know whether the workspace wrapper is applicable until Cargo started
69 // deliberately setting or unsetting it in rust-lang/cargo#9601. We'll use the encoded
70 // rustflags as a proxy for that change for now, but we could instead check version 1.55.
71 if workspace && env::var_os(key:"CARGO_ENCODED_RUSTFLAGS").is_none() {
72 return None;
73 }
74
75 let name: &'static str = if workspace {
76 "RUSTC_WORKSPACE_WRAPPER"
77 } else {
78 "RUSTC_WRAPPER"
79 };
80
81 if let Some(wrapper: OsString) = env::var_os(key:name) {
82 // NB: `OsStr` didn't get `len` or `is_empty` until 1.9.
83 if wrapper != OsString::new() {
84 return Some(wrapper.into());
85 }
86 }
87
88 None
89}
90

Provided by KDAB

Privacy Policy
Learn Rust with the experts
Find out more