diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 00000000..7f7ae210 --- /dev/null +++ b/clippy.toml @@ -0,0 +1,4 @@ +disallowed-methods = [ + { path = "std::env::var_os", reason = "Please use Build::getenv" }, + { path = "std::env::var", reason = "Please use Build::getenv" }, +] diff --git a/dev-tools/cc-test/build.rs b/dev-tools/cc-test/build.rs index d8fc08c0..4adb870c 100644 --- a/dev-tools/cc-test/build.rs +++ b/dev-tools/cc-test/build.rs @@ -1,3 +1,5 @@ +#![allow(clippy::disallowed_methods)] + use std::env; use std::fs; use std::path::{Path, PathBuf}; diff --git a/src/bin/gcc-shim.rs b/src/bin/gcc-shim.rs index f0d219f4..da7a8b35 100644 --- a/src/bin/gcc-shim.rs +++ b/src/bin/gcc-shim.rs @@ -2,6 +2,7 @@ //! It is not intended for users and is not published with the library code to crates.io. #![cfg_attr(test, allow(dead_code))] +#![allow(clippy::disallowed_methods)] use std::env; use std::fs::File; diff --git a/src/command_helpers.rs b/src/command_helpers.rs index e9bd27af..4296d771 100644 --- a/src/command_helpers.rs +++ b/src/command_helpers.rs @@ -27,6 +27,7 @@ pub(crate) struct CargoOutput { impl CargoOutput { pub(crate) fn new() -> Self { + #[allow(clippy::disallowed_methods)] Self { metadata: true, warnings: true, diff --git a/src/lib.rs b/src/lib.rs index dbeb4468..426e37e4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -209,6 +209,7 @@ #![doc(html_root_url = "https://docs.rs/cc/1.0")] #![cfg_attr(test, deny(warnings))] #![deny(missing_docs)] +#![deny(clippy::disallowed_methods)] use std::borrow::Cow; use std::collections::HashMap; @@ -221,7 +222,7 @@ use std::path::{Component, Path, PathBuf}; #[cfg(feature = "parallel")] use std::process::Child; use std::process::Command; -use std::sync::{Arc, Mutex, RwLock}; +use std::sync::{Arc, RwLock}; #[cfg(feature = "parallel")] mod parallel; @@ -249,6 +250,8 @@ struct CompilerFlag { flag: Box, } +type Env = Option>; + /// A builder for compilation of a native library. /// /// A `Build` is the main type of the `cc` crate and is used to control all the @@ -261,7 +264,7 @@ pub struct Build { objects: Vec>, flags: Vec>, flags_supported: Vec>, - known_flag_support_status_cache: Arc>>, + known_flag_support_status_cache: Arc>>, ar_flags: Vec>, asm_flags: Vec>, no_default_flags: bool, @@ -293,11 +296,11 @@ pub struct Build { warnings_into_errors: bool, warnings: Option, extra_warnings: Option, - env_cache: Arc, Option>>>>, - apple_sdk_root_cache: Arc>>, - apple_versions_cache: Arc>>, + env_cache: Arc, Env>>>, + apple_sdk_root_cache: Arc, Arc>>>, + apple_versions_cache: Arc, Arc>>>, emit_rerun_if_env_changed: bool, - cached_compiler_family: Arc, ToolFamily>>>, + cached_compiler_family: Arc, ToolFamily>>>, } /// Represents the types of errors that may occur while using cc-rs. @@ -385,7 +388,7 @@ impl Build { objects: Vec::new(), flags: Vec::new(), flags_supported: Vec::new(), - known_flag_support_status_cache: Arc::new(Mutex::new(HashMap::new())), + known_flag_support_status_cache: Arc::new(RwLock::new(HashMap::new())), ar_flags: Vec::new(), asm_flags: Vec::new(), no_default_flags: false, @@ -418,8 +421,8 @@ impl Build { extra_warnings: None, warnings_into_errors: false, env_cache: Arc::new(RwLock::new(HashMap::new())), - apple_sdk_root_cache: Arc::new(Mutex::new(HashMap::new())), - apple_versions_cache: Arc::new(Mutex::new(HashMap::new())), + apple_sdk_root_cache: Arc::new(RwLock::new(HashMap::new())), + apple_versions_cache: Arc::new(RwLock::new(HashMap::new())), emit_rerun_if_env_changed: true, cached_compiler_family: Arc::default(), } @@ -616,7 +619,7 @@ impl Build { if let Some(is_supported) = self .known_flag_support_status_cache - .lock() + .read() .unwrap() .get(&compiler_flag) .cloned() @@ -680,7 +683,7 @@ impl Build { let is_supported = output.status.success() && output.stderr.is_empty(); self.known_flag_support_status_cache - .lock() + .write() .unwrap() .insert(compiler_flag, is_supported); @@ -1037,7 +1040,7 @@ impl Build { cpp_set_stdlib: V, ) -> &mut Build { let cpp_set_stdlib = cpp_set_stdlib.into().map(Arc::from); - self.cpp_set_stdlib = cpp_set_stdlib.clone(); + self.cpp_set_stdlib.clone_from(&cpp_set_stdlib); self.cpp_link_stdlib = Some(cpp_set_stdlib); self } @@ -1348,7 +1351,7 @@ impl Build { None => "none", }; if cudart != "none" { - if let Some(nvcc) = which(&self.get_compiler().path, None) { + if let Some(nvcc) = self.which(&self.get_compiler().path, None) { // Try to figure out the -L search path. If it fails, // it's on user to specify one by passing it through // RUSTFLAGS environment variable. @@ -1356,7 +1359,7 @@ impl Build { let mut libdir = nvcc; libdir.pop(); // remove 'nvcc' libdir.push(".."); - let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + let target_arch = self.getenv_unwrap_str("CARGO_CFG_TARGET_ARCH")?; if cfg!(target_os = "linux") { libdir.push("targets"); libdir.push(target_arch.to_owned() + "-linux"); @@ -2432,7 +2435,9 @@ impl Build { } else { "ml.exe" }; - let mut cmd = windows_registry::find(&target, tool).unwrap_or_else(|| self.cmd(tool)); + let mut cmd = self + .windows_registry_find(&target, tool) + .unwrap_or_else(|| self.cmd(tool)); cmd.arg("-nologo"); // undocumented, yet working with armasm[64] for directory in self.include_directories.iter() { cmd.arg("-I").arg(&**directory); @@ -2736,13 +2741,13 @@ impl Build { let sdk_path = self.apple_sdk_root(&sdk_details.sdk)?; cmd.args.push("-isysroot".into()); - cmd.args.push(sdk_path.clone()); + cmd.args.push(OsStr::new(&sdk_path).to_owned()); if let AppleArchSpec::Catalyst(_) = arch { // Mac Catalyst uses the macOS SDK, but to compile against and // link to iOS-specific frameworks, we should have the support // library stubs in the include and library search path. - let ios_support = PathBuf::from(sdk_path).join("System/iOSSupport"); + let ios_support = Path::new(&sdk_path).join("System/iOSSupport"); cmd.args.extend([ // Header search path @@ -2812,7 +2817,7 @@ impl Build { traditional }; - let cl_exe = windows_registry::find_tool(target, "cl.exe"); + let cl_exe = self.windows_registry_find_tool(target, "cl.exe"); let tool_opt: Option = self .env_tool(env) @@ -2835,7 +2840,7 @@ impl Build { out_dir, ); if let Some(cc_wrapper) = wrapper { - t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper)); + t.cc_wrapper_path = Some(Path::new(&cc_wrapper).to_owned()); } for arg in args { t.cc_wrapper_args.push(arg.into()); @@ -2926,8 +2931,8 @@ impl Build { &self.cargo_output, out_dir, ); - if let Some(cc_wrapper) = Self::rustc_wrapper_fallback() { - t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper)); + if let Some(cc_wrapper) = self.rustc_wrapper_fallback() { + t.cc_wrapper_path = Some(Path::new(&cc_wrapper).to_owned()); } t } @@ -3026,25 +3031,25 @@ impl Build { } /// Returns a fallback `cc_compiler_wrapper` by introspecting `RUSTC_WRAPPER` - fn rustc_wrapper_fallback() -> Option { + fn rustc_wrapper_fallback(&self) -> Option> { // No explicit CC wrapper was detected, but check if RUSTC_WRAPPER // is defined and is a build accelerator that is compatible with // C/C++ compilers (e.g. sccache) const VALID_WRAPPERS: &[&str] = &["sccache", "cachepot"]; - let rustc_wrapper = std::env::var_os("RUSTC_WRAPPER")?; + let rustc_wrapper = self.getenv("RUSTC_WRAPPER")?; let wrapper_path = Path::new(&rustc_wrapper); let wrapper_stem = wrapper_path.file_stem()?; if VALID_WRAPPERS.contains(&wrapper_stem.to_str()?) { - Some(rustc_wrapper.to_str()?.to_owned()) + Some(rustc_wrapper) } else { None } } /// Returns compiler path, optional modifier name from whitelist, and arguments vec - fn env_tool(&self, name: &str) -> Option<(PathBuf, Option, Vec)> { + fn env_tool(&self, name: &str) -> Option<(PathBuf, Option>, Vec)> { let tool = self.getenv_with_target_prefixes(name).ok()?; let tool = tool.to_string_lossy(); let tool = tool.trim(); @@ -3059,7 +3064,7 @@ impl Build { if Path::new(tool).exists() { return Some(( PathBuf::from(tool), - Self::rustc_wrapper_fallback(), + self.rustc_wrapper_fallback(), Vec::new(), )); } @@ -3092,16 +3097,12 @@ impl Build { None => return None, }; - let file_stem = Path::new(maybe_wrapper) - .file_stem() - .unwrap() - .to_str() - .unwrap(); + let file_stem = Path::new(maybe_wrapper).file_stem()?.to_str()?; if known_wrappers.contains(&file_stem) { if let Some(compiler) = parts.next() { return Some(( compiler.into(), - Some(maybe_wrapper.to_string()), + Some(Arc::::from(OsStr::new(&maybe_wrapper))), parts.map(|s| s.to_string()).collect(), )); } @@ -3109,7 +3110,7 @@ impl Build { Some(( maybe_wrapper.into(), - Self::rustc_wrapper_fallback(), + self.rustc_wrapper_fallback(), parts.map(|s| s.to_string()).collect(), )) } @@ -3284,8 +3285,12 @@ impl Build { let compiler = self.get_base_compiler().ok()?; if compiler.is_like_clang() { name = format!("llvm-{}", tool).into(); - search_programs(&mut self.cmd(&compiler.path), &name, &self.cargo_output) - .map(|name| self.cmd(name)) + self.search_programs( + &mut self.cmd(&compiler.path), + &name, + &self.cargo_output, + ) + .map(|name| self.cmd(name)) } else { None } @@ -3319,10 +3324,10 @@ impl Build { // next to 'clang-cl' and use 'search_programs()' to locate // 'llvm-lib'. This is because 'clang-cl' doesn't support // the -print-search-dirs option. - if let Some(mut cmd) = which(&compiler.path, None) { + if let Some(mut cmd) = self.which(&compiler.path, None) { cmd.pop(); cmd.push("llvm-lib.exe"); - if let Some(llvm_lib) = which(&cmd, None) { + if let Some(llvm_lib) = self.which(&cmd, None) { llvm_lib.to_str().unwrap().clone_into(&mut lib); } } @@ -3330,7 +3335,7 @@ impl Build { if lib.is_empty() { name = PathBuf::from("lib.exe"); - let mut cmd = match windows_registry::find(&target, "lib.exe") { + let mut cmd = match self.windows_registry_find(&target, "lib.exe") { Some(t) => t, None => self.cmd("lib.exe"), }; @@ -3386,142 +3391,143 @@ impl Build { } fn prefix_for_target(&self, target: &str) -> Option> { - // Put aside RUSTC_LINKER's prefix to be used as second choice, after CROSS_COMPILE - let linker_prefix = self.getenv("RUSTC_LINKER").and_then(|var| { - var.to_string_lossy() - .strip_suffix("-gcc") - .map(str::to_string) - .map(Cow::Owned) - }); // CROSS_COMPILE is of the form: "arm-linux-gnueabi-" - let cc_env = self.getenv("CROSS_COMPILE"); - let cross_compile = cc_env + self.getenv("CROSS_COMPILE") .as_deref() .map(|s| s.to_string_lossy().trim_end_matches('-').to_owned()) - .map(Cow::Owned); - cross_compile.or(linker_prefix).or_else(|| { - match target { - // Note: there is no `aarch64-pc-windows-gnu` target, only `-gnullvm` - "aarch64-pc-windows-gnullvm" => Some("aarch64-w64-mingw32"), - "aarch64-uwp-windows-gnu" => Some("aarch64-w64-mingw32"), - "aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu"), - "aarch64-unknown-linux-musl" => Some("aarch64-linux-musl"), - "aarch64-unknown-netbsd" => Some("aarch64--netbsd"), - "arm-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), - "armv4t-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), - "armv5te-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), - "armv5te-unknown-linux-musleabi" => Some("arm-linux-gnueabi"), - "arm-frc-linux-gnueabi" => Some("arm-frc-linux-gnueabi"), - "arm-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), - "arm-unknown-linux-musleabi" => Some("arm-linux-musleabi"), - "arm-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), - "arm-unknown-netbsd-eabi" => Some("arm--netbsdelf-eabi"), - "armv6-unknown-netbsd-eabihf" => Some("armv6--netbsdelf-eabihf"), - "armv7-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), - "armv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), - "armv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), - "armv7neon-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), - "armv7neon-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), - "thumbv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), - "thumbv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), - "thumbv7neon-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), - "thumbv7neon-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), - "armv7-unknown-netbsd-eabihf" => Some("armv7--netbsdelf-eabihf"), - "hexagon-unknown-linux-musl" => Some("hexagon-linux-musl"), - "i586-unknown-linux-musl" => Some("musl"), - "i686-pc-windows-gnu" => Some("i686-w64-mingw32"), - "i686-uwp-windows-gnu" => Some("i686-w64-mingw32"), - "i686-unknown-linux-gnu" => self.find_working_gnu_prefix(&[ - "i686-linux-gnu", - "x86_64-linux-gnu", // transparently support gcc-multilib - ]), // explicit None if not found, so caller knows to fall back - "i686-unknown-linux-musl" => Some("musl"), - "i686-unknown-netbsd" => Some("i486--netbsdelf"), - "loongarch64-unknown-linux-gnu" => Some("loongarch64-linux-gnu"), - "mips-unknown-linux-gnu" => Some("mips-linux-gnu"), - "mips-unknown-linux-musl" => Some("mips-linux-musl"), - "mipsel-unknown-linux-gnu" => Some("mipsel-linux-gnu"), - "mipsel-unknown-linux-musl" => Some("mipsel-linux-musl"), - "mips64-unknown-linux-gnuabi64" => Some("mips64-linux-gnuabi64"), - "mips64el-unknown-linux-gnuabi64" => Some("mips64el-linux-gnuabi64"), - "mipsisa32r6-unknown-linux-gnu" => Some("mipsisa32r6-linux-gnu"), - "mipsisa32r6el-unknown-linux-gnu" => Some("mipsisa32r6el-linux-gnu"), - "mipsisa64r6-unknown-linux-gnuabi64" => Some("mipsisa64r6-linux-gnuabi64"), - "mipsisa64r6el-unknown-linux-gnuabi64" => Some("mipsisa64r6el-linux-gnuabi64"), - "powerpc-unknown-linux-gnu" => Some("powerpc-linux-gnu"), - "powerpc-unknown-linux-gnuspe" => Some("powerpc-linux-gnuspe"), - "powerpc-unknown-netbsd" => Some("powerpc--netbsd"), - "powerpc64-unknown-linux-gnu" => Some("powerpc-linux-gnu"), - "powerpc64le-unknown-linux-gnu" => Some("powerpc64le-linux-gnu"), - "riscv32i-unknown-none-elf" => self.find_working_gnu_prefix(&[ - "riscv32-unknown-elf", - "riscv64-unknown-elf", - "riscv-none-embed", - ]), - "riscv32imac-esp-espidf" => Some("riscv32-esp-elf"), - "riscv32imac-unknown-none-elf" => self.find_working_gnu_prefix(&[ - "riscv32-unknown-elf", - "riscv64-unknown-elf", - "riscv-none-embed", - ]), - "riscv32imac-unknown-xous-elf" => self.find_working_gnu_prefix(&[ - "riscv32-unknown-elf", - "riscv64-unknown-elf", - "riscv-none-embed", - ]), - "riscv32imc-esp-espidf" => Some("riscv32-esp-elf"), - "riscv32imc-unknown-none-elf" => self.find_working_gnu_prefix(&[ - "riscv32-unknown-elf", - "riscv64-unknown-elf", - "riscv-none-embed", - ]), - "riscv64gc-unknown-none-elf" => self.find_working_gnu_prefix(&[ - "riscv64-unknown-elf", - "riscv32-unknown-elf", - "riscv-none-embed", - ]), - "riscv64imac-unknown-none-elf" => self.find_working_gnu_prefix(&[ - "riscv64-unknown-elf", - "riscv32-unknown-elf", - "riscv-none-embed", - ]), - "riscv64gc-unknown-linux-gnu" => Some("riscv64-linux-gnu"), - "riscv32gc-unknown-linux-gnu" => Some("riscv32-linux-gnu"), - "riscv64gc-unknown-linux-musl" => Some("riscv64-linux-musl"), - "riscv32gc-unknown-linux-musl" => Some("riscv32-linux-musl"), - "riscv64gc-unknown-netbsd" => Some("riscv64--netbsd"), - "s390x-unknown-linux-gnu" => Some("s390x-linux-gnu"), - "sparc-unknown-linux-gnu" => Some("sparc-linux-gnu"), - "sparc64-unknown-linux-gnu" => Some("sparc64-linux-gnu"), - "sparc64-unknown-netbsd" => Some("sparc64--netbsd"), - "sparcv9-sun-solaris" => Some("sparcv9-sun-solaris"), - "armv7a-none-eabi" => Some("arm-none-eabi"), - "armv7a-none-eabihf" => Some("arm-none-eabi"), - "armebv7r-none-eabi" => Some("arm-none-eabi"), - "armebv7r-none-eabihf" => Some("arm-none-eabi"), - "armv7r-none-eabi" => Some("arm-none-eabi"), - "armv7r-none-eabihf" => Some("arm-none-eabi"), - "armv8r-none-eabihf" => Some("arm-none-eabi"), - "thumbv6m-none-eabi" => Some("arm-none-eabi"), - "thumbv7em-none-eabi" => Some("arm-none-eabi"), - "thumbv7em-none-eabihf" => Some("arm-none-eabi"), - "thumbv7m-none-eabi" => Some("arm-none-eabi"), - "thumbv8m.base-none-eabi" => Some("arm-none-eabi"), - "thumbv8m.main-none-eabi" => Some("arm-none-eabi"), - "thumbv8m.main-none-eabihf" => Some("arm-none-eabi"), - "x86_64-pc-windows-gnu" => Some("x86_64-w64-mingw32"), - "x86_64-pc-windows-gnullvm" => Some("x86_64-w64-mingw32"), - "x86_64-uwp-windows-gnu" => Some("x86_64-w64-mingw32"), - "x86_64-rumprun-netbsd" => Some("x86_64-rumprun-netbsd"), - "x86_64-unknown-linux-gnu" => self.find_working_gnu_prefix(&[ - "x86_64-linux-gnu", // rustfmt wrap - ]), // explicit None if not found, so caller knows to fall back - "x86_64-unknown-linux-musl" => Some("musl"), - "x86_64-unknown-netbsd" => Some("x86_64--netbsd"), - _ => None, - } - .map(Cow::Borrowed) - }) + .map(Cow::Owned) + .or_else(|| { + // Put aside RUSTC_LINKER's prefix to be used as second choice, after CROSS_COMPILE + self.getenv("RUSTC_LINKER").and_then(|var| { + var.to_string_lossy() + .strip_suffix("-gcc") + .map(str::to_string) + .map(Cow::Owned) + }) + }) + .or_else(|| { + match target { + // Note: there is no `aarch64-pc-windows-gnu` target, only `-gnullvm` + "aarch64-pc-windows-gnullvm" => Some("aarch64-w64-mingw32"), + "aarch64-uwp-windows-gnu" => Some("aarch64-w64-mingw32"), + "aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu"), + "aarch64-unknown-linux-musl" => Some("aarch64-linux-musl"), + "aarch64-unknown-netbsd" => Some("aarch64--netbsd"), + "arm-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv4t-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv5te-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv5te-unknown-linux-musleabi" => Some("arm-linux-gnueabi"), + "arm-frc-linux-gnueabi" => Some("arm-frc-linux-gnueabi"), + "arm-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "arm-unknown-linux-musleabi" => Some("arm-linux-musleabi"), + "arm-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "arm-unknown-netbsd-eabi" => Some("arm--netbsdelf-eabi"), + "armv6-unknown-netbsd-eabihf" => Some("armv6--netbsdelf-eabihf"), + "armv7-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "armv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "armv7neon-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "armv7neon-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "thumbv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "thumbv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "thumbv7neon-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "thumbv7neon-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "armv7-unknown-netbsd-eabihf" => Some("armv7--netbsdelf-eabihf"), + "hexagon-unknown-linux-musl" => Some("hexagon-linux-musl"), + "i586-unknown-linux-musl" => Some("musl"), + "i686-pc-windows-gnu" => Some("i686-w64-mingw32"), + "i686-uwp-windows-gnu" => Some("i686-w64-mingw32"), + "i686-unknown-linux-gnu" => self.find_working_gnu_prefix(&[ + "i686-linux-gnu", + "x86_64-linux-gnu", // transparently support gcc-multilib + ]), // explicit None if not found, so caller knows to fall back + "i686-unknown-linux-musl" => Some("musl"), + "i686-unknown-netbsd" => Some("i486--netbsdelf"), + "loongarch64-unknown-linux-gnu" => Some("loongarch64-linux-gnu"), + "mips-unknown-linux-gnu" => Some("mips-linux-gnu"), + "mips-unknown-linux-musl" => Some("mips-linux-musl"), + "mipsel-unknown-linux-gnu" => Some("mipsel-linux-gnu"), + "mipsel-unknown-linux-musl" => Some("mipsel-linux-musl"), + "mips64-unknown-linux-gnuabi64" => Some("mips64-linux-gnuabi64"), + "mips64el-unknown-linux-gnuabi64" => Some("mips64el-linux-gnuabi64"), + "mipsisa32r6-unknown-linux-gnu" => Some("mipsisa32r6-linux-gnu"), + "mipsisa32r6el-unknown-linux-gnu" => Some("mipsisa32r6el-linux-gnu"), + "mipsisa64r6-unknown-linux-gnuabi64" => Some("mipsisa64r6-linux-gnuabi64"), + "mipsisa64r6el-unknown-linux-gnuabi64" => Some("mipsisa64r6el-linux-gnuabi64"), + "powerpc-unknown-linux-gnu" => Some("powerpc-linux-gnu"), + "powerpc-unknown-linux-gnuspe" => Some("powerpc-linux-gnuspe"), + "powerpc-unknown-netbsd" => Some("powerpc--netbsd"), + "powerpc64-unknown-linux-gnu" => Some("powerpc-linux-gnu"), + "powerpc64le-unknown-linux-gnu" => Some("powerpc64le-linux-gnu"), + "riscv32i-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv32-unknown-elf", + "riscv64-unknown-elf", + "riscv-none-embed", + ]), + "riscv32imac-esp-espidf" => Some("riscv32-esp-elf"), + "riscv32imac-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv32-unknown-elf", + "riscv64-unknown-elf", + "riscv-none-embed", + ]), + "riscv32imac-unknown-xous-elf" => self.find_working_gnu_prefix(&[ + "riscv32-unknown-elf", + "riscv64-unknown-elf", + "riscv-none-embed", + ]), + "riscv32imc-esp-espidf" => Some("riscv32-esp-elf"), + "riscv32imc-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv32-unknown-elf", + "riscv64-unknown-elf", + "riscv-none-embed", + ]), + "riscv64gc-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv64-unknown-elf", + "riscv32-unknown-elf", + "riscv-none-embed", + ]), + "riscv64imac-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv64-unknown-elf", + "riscv32-unknown-elf", + "riscv-none-embed", + ]), + "riscv64gc-unknown-linux-gnu" => Some("riscv64-linux-gnu"), + "riscv32gc-unknown-linux-gnu" => Some("riscv32-linux-gnu"), + "riscv64gc-unknown-linux-musl" => Some("riscv64-linux-musl"), + "riscv32gc-unknown-linux-musl" => Some("riscv32-linux-musl"), + "riscv64gc-unknown-netbsd" => Some("riscv64--netbsd"), + "s390x-unknown-linux-gnu" => Some("s390x-linux-gnu"), + "sparc-unknown-linux-gnu" => Some("sparc-linux-gnu"), + "sparc64-unknown-linux-gnu" => Some("sparc64-linux-gnu"), + "sparc64-unknown-netbsd" => Some("sparc64--netbsd"), + "sparcv9-sun-solaris" => Some("sparcv9-sun-solaris"), + "armv7a-none-eabi" => Some("arm-none-eabi"), + "armv7a-none-eabihf" => Some("arm-none-eabi"), + "armebv7r-none-eabi" => Some("arm-none-eabi"), + "armebv7r-none-eabihf" => Some("arm-none-eabi"), + "armv7r-none-eabi" => Some("arm-none-eabi"), + "armv7r-none-eabihf" => Some("arm-none-eabi"), + "armv8r-none-eabihf" => Some("arm-none-eabi"), + "thumbv6m-none-eabi" => Some("arm-none-eabi"), + "thumbv7em-none-eabi" => Some("arm-none-eabi"), + "thumbv7em-none-eabihf" => Some("arm-none-eabi"), + "thumbv7m-none-eabi" => Some("arm-none-eabi"), + "thumbv8m.base-none-eabi" => Some("arm-none-eabi"), + "thumbv8m.main-none-eabi" => Some("arm-none-eabi"), + "thumbv8m.main-none-eabihf" => Some("arm-none-eabi"), + "x86_64-pc-windows-gnu" => Some("x86_64-w64-mingw32"), + "x86_64-pc-windows-gnullvm" => Some("x86_64-w64-mingw32"), + "x86_64-uwp-windows-gnu" => Some("x86_64-w64-mingw32"), + "x86_64-rumprun-netbsd" => Some("x86_64-rumprun-netbsd"), + "x86_64-unknown-linux-gnu" => self.find_working_gnu_prefix(&[ + "x86_64-linux-gnu", // rustfmt wrap + ]), // explicit None if not found, so caller knows to fall back + "x86_64-unknown-linux-musl" => Some("musl"), + "x86_64-unknown-netbsd" => Some("x86_64--netbsd"), + _ => None, + } + .map(Cow::Borrowed) + }) } /// Some platforms have multiple, compatible, canonical prefixes. Look through @@ -3534,7 +3540,7 @@ impl Build { // Loop through PATH entries searching for each toolchain. This ensures that we // are more likely to discover the toolchain early on, because chances are good // that the desired toolchain is in one of the higher-priority paths. - env::var_os("PATH") + self.getenv("PATH") .as_ref() .and_then(|path_entries| { env::split_paths(path_entries).find_map(|path_entry| { @@ -3555,16 +3561,6 @@ impl Build { .or_else(|| prefixes.first().copied()) } - fn getenv_unwrap_str(&self, v: &str) -> Result { - let env = self.getenv_unwrap(v)?; - env.to_str().map(String::from).ok_or_else(|| { - Error::new( - ErrorKind::EnvVarNotFound, - format!("Environment variable {} is not valid utf-8.", v), - ) - }) - } - fn get_target(&self) -> Result, Error> { match &self.target { Some(t) => Ok(Cow::Borrowed(t)), @@ -3619,7 +3615,9 @@ impl Build { fn get_out_dir(&self) -> Result, Error> { match &self.out_dir { Some(p) => Ok(Cow::Borrowed(&**p)), - None => env::var_os("OUT_DIR") + None => self + .getenv("OUT_DIR") + .as_deref() .map(PathBuf::from) .map(Cow::Owned) .ok_or_else(|| { @@ -3631,6 +3629,7 @@ impl Build { } } + #[allow(clippy::disallowed_methods)] fn getenv(&self, v: &str) -> Option> { // Returns true for environment variables cargo sets for build scripts: // https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts @@ -3673,6 +3672,16 @@ impl Build { } } + fn getenv_unwrap_str(&self, v: &str) -> Result { + let env = self.getenv_unwrap(v)?; + env.to_str().map(String::from).ok_or_else(|| { + Error::new( + ErrorKind::EnvVarNotFound, + format!("Environment variable {} is not valid utf-8.", v), + ) + }) + } + fn getenv_with_target_prefixes(&self, var_base: &str) -> Result, Error> { let target = self.get_target()?; let host = self.get_host()?; @@ -3698,7 +3707,7 @@ impl Build { .getenv_with_target_prefixes(name)? .to_string_lossy() .split_ascii_whitespace() - .map(|slice| slice.to_string()) + .map(ToString::to_string) .collect()) } @@ -3714,54 +3723,39 @@ impl Build { Ok(()) } - fn apple_sdk_root(&self, sdk: &str) -> Result { + fn apple_sdk_root_inner(&self, sdk: &str) -> Result, Error> { // Code copied from rustc's compiler/rustc_codegen_ssa/src/back/link.rs. - if let Some(sdkroot) = env::var_os("SDKROOT") { - let p = PathBuf::from(sdkroot); - let sdkroot = p.to_string_lossy(); + if let Some(sdkroot) = self.getenv("SDKROOT") { + let p = Path::new(&sdkroot); + let does_sdkroot_contain = |strings: &[&str]| { + let sdkroot_str = p.to_string_lossy(); + strings.iter().any(|s| sdkroot_str.contains(s)) + }; match sdk { // Ignore `SDKROOT` if it's clearly set for the wrong platform. "appletvos" - if sdkroot.contains("TVSimulator.platform") - || sdkroot.contains("MacOSX.platform") => {} + if does_sdkroot_contain(&["TVSimulator.platform", "MacOSX.platform"]) => {} "appletvsimulator" - if sdkroot.contains("TVOS.platform") || sdkroot.contains("MacOSX.platform") => { - } + if does_sdkroot_contain(&["TVOS.platform", "MacOSX.platform"]) => {} "iphoneos" - if sdkroot.contains("iPhoneSimulator.platform") - || sdkroot.contains("MacOSX.platform") => {} + if does_sdkroot_contain(&["iPhoneSimulator.platform", "MacOSX.platform"]) => {} "iphonesimulator" - if sdkroot.contains("iPhoneOS.platform") - || sdkroot.contains("MacOSX.platform") => {} + if does_sdkroot_contain(&["iPhoneOS.platform", "MacOSX.platform"]) => {} "macosx10.15" - if sdkroot.contains("iPhoneOS.platform") - || sdkroot.contains("iPhoneSimulator.platform") => {} + if does_sdkroot_contain(&["iPhoneOS.platform", "iPhoneSimulator.platform"]) => { + } "watchos" - if sdkroot.contains("WatchSimulator.platform") - || sdkroot.contains("MacOSX.platform") => {} + if does_sdkroot_contain(&["WatchSimulator.platform", "MacOSX.platform"]) => {} "watchsimulator" - if sdkroot.contains("WatchOS.platform") - || sdkroot.contains("MacOSX.platform") => {} - "xros" - if sdkroot.contains("XRSimulator.platform") - || sdkroot.contains("MacOSX.platform") => {} - "xrsimulator" - if sdkroot.contains("XROS.platform") || sdkroot.contains("MacOSX.platform") => { - } + if does_sdkroot_contain(&["WatchOS.platform", "MacOSX.platform"]) => {} + "xros" if does_sdkroot_contain(&["XRSimulator.platform", "MacOSX.platform"]) => {} + "xrsimulator" if does_sdkroot_contain(&["XROS.platform", "MacOSX.platform"]) => {} // Ignore `SDKROOT` if it's not a valid path. _ if !p.is_absolute() || p == Path::new("/") || !p.exists() => {} - _ => return Ok(p.into()), + _ => return Ok(sdkroot), } } - let mut cache = self - .apple_sdk_root_cache - .lock() - .expect("apple_sdk_root_cache lock failed"); - if let Some(ret) = cache.get(sdk) { - return Ok(ret.clone()); - } - let sdk_path = run_output( self.cmd("xcrun") .arg("--show-sdk-path") @@ -3780,22 +3774,39 @@ impl Build { )); } }; - let ret: OsString = sdk_path.trim().into(); - cache.insert(sdk.into(), ret.clone()); - Ok(ret) + Ok(Arc::from(OsStr::new(sdk_path.trim()))) } - fn apple_deployment_version(&self, os: AppleOs, arch_str: Option<&str>, sdk: &str) -> String { - let default_deployment_from_sdk = || { - let mut cache = self - .apple_versions_cache - .lock() - .expect("apple_versions_cache lock failed"); + fn apple_sdk_root(&self, sdk: &str) -> Result, Error> { + if let Some(ret) = self + .apple_sdk_root_cache + .read() + .expect("apple_sdk_root_cache lock failed") + .get(sdk) + .cloned() + { + return Ok(ret); + } + let sdk_path = self.apple_sdk_root_inner(sdk)?; + self.apple_sdk_root_cache + .write() + .expect("apple_sdk_root_cache lock failed") + .insert(sdk.into(), sdk_path.clone()); + Ok(sdk_path) + } - if let Some(ret) = cache.get(sdk) { - return Some(ret.clone()); - } + fn apple_deployment_version(&self, os: AppleOs, arch_str: Option<&str>, sdk: &str) -> Arc { + if let Some(ret) = self + .apple_versions_cache + .read() + .expect("apple_versions_cache lock failed") + .get(sdk) + .cloned() + { + return ret; + } + let default_deployment_from_sdk = || -> Option> { let version = run_output( self.cmd("xcrun") .arg("--show-sdk-version") @@ -3806,27 +3817,27 @@ impl Build { ) .ok()?; - let version = std::str::from_utf8(&version).ok()?.trim().to_owned(); - - cache.insert(sdk.into(), version.clone()); - Some(version) + Some(Arc::from(std::str::from_utf8(&version).ok()?.trim())) }; - let deployment_from_env = |name: &str| { - // note this isn't hit in production codepaths, its mostly just for tests which don't + let deployment_from_env = |name: &str| -> Option> { + // note that self.env isn't hit in production codepaths, its mostly just for tests which don't // set the real env - if let Some((_, v)) = self.env.iter().find(|(k, _)| &**k == OsStr::new(name)) { - Some(v.to_str().unwrap().to_string()) - } else { - env::var(name).ok() - } + self.env + .iter() + .find(|(k, _)| &**k == OsStr::new(name)) + .map(|(_, v)| v) + .cloned() + .or_else(|| self.getenv(name))? + .to_str() + .map(Arc::from) }; // Determines if the acquired deployment target is too low to support modern C++ on some Apple platform. // // A long time ago they used libstdc++, but since macOS 10.9 and iOS 7 libc++ has been the library the SDKs provide to link against. // If a `cc`` config wants to use C++, we round up to these versions as the baseline. - let maybe_cpp_version_baseline = |deployment_target_ver: String| -> Option { + let maybe_cpp_version_baseline = |deployment_target_ver: Arc| -> Option> { if !self.cpp { return Some(deployment_target_ver); } @@ -3880,7 +3891,7 @@ impl Build { // // The ordering of env -> XCode SDK -> old rustc defaults is intentional for performance when using // an explicit target. - match os { + let version: Arc = match os { AppleOs::MacOs => deployment_from_env("MACOSX_DEPLOYMENT_TARGET") .and_then(maybe_cpp_version_baseline) .or_else(default_deployment_from_sdk) @@ -3888,8 +3899,8 @@ impl Build { if arch_str == Some("aarch64") { "11.0".into() } else { - let default = "10.7"; - maybe_cpp_version_baseline(default.into()).unwrap_or_else(|| default.into()) + let default: Arc = Arc::from("10.7"); + maybe_cpp_version_baseline(default.clone()).unwrap_or(default) } }), @@ -3909,7 +3920,14 @@ impl Build { AppleOs::VisionOS => deployment_from_env("XROS_DEPLOYMENT_TARGET") .or_else(default_deployment_from_sdk) .unwrap_or_else(|| "1.0".into()), - } + }; + + self.apple_versions_cache + .write() + .expect("apple_versions_cache lock failed") + .insert(sdk.into(), version.clone()); + + version } fn wasi_sysroot(&self) -> Result, Error> { @@ -3929,6 +3947,71 @@ impl Build { .filter(|file| file.extension() == Some(OsStr::new("cu"))) .count() } + + fn which(&self, tool: &Path, path_entries: Option<&OsStr>) -> Option { + fn check_exe(mut exe: PathBuf) -> Option { + let exe_ext = std::env::consts::EXE_EXTENSION; + let check = + exe.exists() || (!exe_ext.is_empty() && exe.set_extension(exe_ext) && exe.exists()); + check.then_some(exe) + } + + // Loop through PATH entries searching for the |tool|. + let find_exe_in_path = |path_entries: &OsStr| -> Option { + env::split_paths(path_entries).find_map(|path_entry| check_exe(path_entry.join(tool))) + }; + + // If |tool| is not just one "word," assume it's an actual path... + if tool.components().count() > 1 { + check_exe(PathBuf::from(tool)) + } else { + path_entries + .and_then(find_exe_in_path) + .or_else(|| find_exe_in_path(&self.getenv("PATH")?)) + } + } + + /// search for |prog| on 'programs' path in '|cc| -print-search-dirs' output + fn search_programs( + &self, + cc: &mut Command, + prog: &Path, + cargo_output: &CargoOutput, + ) -> Option { + let search_dirs = run_output( + cc.arg("-print-search-dirs"), + "cc", + // this doesn't concern the compilation so we always want to show warnings. + cargo_output, + ) + .ok()?; + // clang driver appears to be forcing UTF-8 output even on Windows, + // hence from_utf8 is assumed to be usable in all cases. + let search_dirs = std::str::from_utf8(&search_dirs).ok()?; + for dirs in search_dirs.split(|c| c == '\r' || c == '\n') { + if let Some(path) = dirs.strip_prefix("programs: =") { + return self.which(prog, Some(OsStr::new(path))); + } + } + None + } + + fn windows_registry_find(&self, target: &str, tool: &str) -> Option { + self.windows_registry_find_tool(target, tool) + .map(|c| c.to_command()) + } + + fn windows_registry_find_tool(&self, target: &str, tool: &str) -> Option { + struct BuildEnvGetter<'s>(&'s Build); + + impl windows_registry::EnvGetter for BuildEnvGetter<'_> { + fn get_env(&self, name: &str) -> Option { + self.0.getenv(name).map(windows_registry::Env::Arced) + } + } + + windows_registry::find_tool_inner(target, tool, &BuildEnvGetter(self)) + } } impl Default for Build { @@ -4028,27 +4111,6 @@ fn android_clang_compiler_uses_target_arg_internally(clang_path: &Path) -> bool false } -#[test] -fn test_android_clang_compiler_uses_target_arg_internally() { - for version in 16..21 { - assert!(android_clang_compiler_uses_target_arg_internally( - &PathBuf::from(format!("armv7a-linux-androideabi{}-clang", version)) - )); - assert!(android_clang_compiler_uses_target_arg_internally( - &PathBuf::from(format!("armv7a-linux-androideabi{}-clang++", version)) - )); - } - assert!(!android_clang_compiler_uses_target_arg_internally( - &PathBuf::from("clang-i686-linux-android") - )); - assert!(!android_clang_compiler_uses_target_arg_internally( - &PathBuf::from("clang") - )); - assert!(!android_clang_compiler_uses_target_arg_internally( - &PathBuf::from("clang++") - )); -} - fn autodetect_android_compiler(target: &str, host: &str, gnu: &str, clang: &str) -> String { let new_clang_key = match target { "aarch64-linux-android" => Some("aarch64"), @@ -4117,50 +4179,6 @@ fn map_darwin_target_from_rust_to_compiler_architecture(target: &str) -> Option< } } -fn which(tool: &Path, path_entries: Option) -> Option { - fn check_exe(exe: &mut PathBuf) -> bool { - let exe_ext = std::env::consts::EXE_EXTENSION; - exe.exists() || (!exe_ext.is_empty() && exe.set_extension(exe_ext) && exe.exists()) - } - - // If |tool| is not just one "word," assume it's an actual path... - if tool.components().count() > 1 { - let mut exe = PathBuf::from(tool); - return if check_exe(&mut exe) { Some(exe) } else { None }; - } - - // Loop through PATH entries searching for the |tool|. - let path_entries = path_entries.or(env::var_os("PATH"))?; - env::split_paths(&path_entries).find_map(|path_entry| { - let mut exe = path_entry.join(tool); - if check_exe(&mut exe) { - Some(exe) - } else { - None - } - }) -} - -// search for |prog| on 'programs' path in '|cc| -print-search-dirs' output -fn search_programs(cc: &mut Command, prog: &Path, cargo_output: &CargoOutput) -> Option { - let search_dirs = run_output( - cc.arg("-print-search-dirs"), - "cc", - // this doesn't concern the compilation so we always want to show warnings. - cargo_output, - ) - .ok()?; - // clang driver appears to be forcing UTF-8 output even on Windows, - // hence from_utf8 is assumed to be usable in all cases. - let search_dirs = std::str::from_utf8(&search_dirs).ok()?; - for dirs in search_dirs.split(|c| c == '\r' || c == '\n') { - if let Some(path) = dirs.strip_prefix("programs: =") { - return which(prog, Some(OsString::from(path))); - } - } - None -} - #[derive(Clone, Copy, PartialEq)] enum AsmFileExt { /// `.asm` files. On MSVC targets, we assume these should be passed to MASM @@ -4185,3 +4203,29 @@ impl AsmFileExt { None } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_android_clang_compiler_uses_target_arg_internally() { + for version in 16..21 { + assert!(android_clang_compiler_uses_target_arg_internally( + &PathBuf::from(format!("armv7a-linux-androideabi{}-clang", version)) + )); + assert!(android_clang_compiler_uses_target_arg_internally( + &PathBuf::from(format!("armv7a-linux-androideabi{}-clang++", version)) + )); + } + assert!(!android_clang_compiler_uses_target_arg_internally( + &PathBuf::from("clang-i686-linux-android") + )); + assert!(!android_clang_compiler_uses_target_arg_internally( + &PathBuf::from("clang") + )); + assert!(!android_clang_compiler_uses_target_arg_internally( + &PathBuf::from("clang++") + )); + } +} diff --git a/src/tool.rs b/src/tool.rs index f0f5b952..72fc23b5 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -6,7 +6,7 @@ use std::{ io::Write, path::{Path, PathBuf}, process::{Command, Stdio}, - sync::Mutex, + sync::RwLock, }; use crate::{ @@ -40,7 +40,7 @@ pub struct Tool { impl Tool { pub(crate) fn new( path: PathBuf, - cached_compiler_family: &Mutex, ToolFamily>>, + cached_compiler_family: &RwLock, ToolFamily>>, cargo_output: &CargoOutput, out_dir: Option<&Path>, ) -> Self { @@ -57,7 +57,7 @@ impl Tool { pub(crate) fn with_clang_driver( path: PathBuf, clang_driver: Option<&str>, - cached_compiler_family: &Mutex, ToolFamily>>, + cached_compiler_family: &RwLock, ToolFamily>>, cargo_output: &CargoOutput, out_dir: Option<&Path>, ) -> Self { @@ -90,7 +90,7 @@ impl Tool { path: PathBuf, clang_driver: Option<&str>, cuda: bool, - cached_compiler_family: &Mutex, ToolFamily>>, + cached_compiler_family: &RwLock, ToolFamily>>, cargo_output: &CargoOutput, out_dir: Option<&Path>, ) -> Self { @@ -186,13 +186,13 @@ impl Tool { } } let detect_family = |path: &Path| -> Result { - if let Some(family) = cached_compiler_family.lock().unwrap().get(path) { + if let Some(family) = cached_compiler_family.read().unwrap().get(path) { return Ok(*family); } let family = detect_family_inner(path, cargo_output, out_dir)?; cached_compiler_family - .lock() + .write() .unwrap() .insert(path.into(), family); Ok(family) diff --git a/src/utilities.rs b/src/utilities.rs index d09ffff4..073e617b 100644 --- a/src/utilities.rs +++ b/src/utilities.rs @@ -15,7 +15,7 @@ where { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let len = self.slice.len(); - for (index, os_str) in self.slice.into_iter().enumerate() { + for (index, os_str) in self.slice.iter().enumerate() { // TODO: Use OsStr::display once it is stablised, // Path and OsStr has the same `Display` impl write!(f, "{}", Path::new(os_str).display())?; diff --git a/src/windows/find_tools.rs b/src/windows/find_tools.rs index 015b01df..a7be3c32 100644 --- a/src/windows/find_tools.rs +++ b/src/windows/find_tools.rs @@ -14,7 +14,14 @@ #![allow(clippy::upper_case_acronyms)] -use std::process::Command; +use std::{ + env, + ffi::{OsStr, OsString}, + ops::Deref, + path::PathBuf, + process::Command, + sync::Arc, +}; use crate::Tool; use crate::ToolFamily; @@ -36,6 +43,50 @@ impl<'a> From> for &'a str { } } +pub(crate) enum Env { + Owned(OsString), + Arced(Arc), +} + +impl AsRef for Env { + fn as_ref(&self) -> &OsStr { + self.deref() + } +} + +impl Deref for Env { + type Target = OsStr; + + fn deref(&self) -> &Self::Target { + match self { + Env::Owned(os_str) => os_str, + Env::Arced(os_str) => os_str, + } + } +} + +impl From for PathBuf { + fn from(env: Env) -> Self { + match env { + Env::Owned(os_str) => PathBuf::from(os_str), + Env::Arced(os_str) => PathBuf::from(os_str.deref()), + } + } +} + +pub(crate) trait EnvGetter { + fn get_env(&self, name: &'static str) -> Option; +} + +struct StdEnvGetter; + +impl EnvGetter for StdEnvGetter { + #[allow(clippy::disallowed_methods)] + fn get_env(&self, name: &'static str) -> Option { + env::var_os(name).map(Env::Owned) + } +} + /// Attempts to find a tool within an MSVC installation using the Windows /// registry as a point to search from. /// @@ -56,6 +107,14 @@ pub fn find(target: &str, tool: &str) -> Option { /// operation (finding a MSVC tool in a local install) but instead returns a /// `Tool` which may be introspected. pub fn find_tool(target: &str, tool: &str) -> Option { + find_tool_inner(target, tool, &StdEnvGetter) +} + +pub(crate) fn find_tool_inner( + target: &str, + tool: &str, + env_getter: &dyn EnvGetter, +) -> Option { // This logic is all tailored for MSVC, if we're not that then bail out // early. if !target.contains("msvc") { @@ -68,13 +127,13 @@ pub fn find_tool(target: &str, tool: &str) -> Option { // Looks like msbuild isn't located in the same location as other tools like // cl.exe and lib.exe. if tool.contains("msbuild") { - return impl_::find_msbuild(target); + return impl_::find_msbuild(target, env_getter); } // Looks like devenv isn't located in the same location as other tools like // cl.exe and lib.exe. if tool.contains("devenv") { - return impl_::find_devenv(target); + return impl_::find_devenv(target, env_getter); } // Ok, if we're here, now comes the fun part of the probing. Default shells @@ -84,10 +143,10 @@ pub fn find_tool(target: &str, tool: &str) -> Option { // environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that // the tool is actually usable. - impl_::find_msvc_environment(tool, target) - .or_else(|| impl_::find_msvc_15plus(tool, target)) - .or_else(|| impl_::find_msvc_14(tool, target)) - .or_else(|| impl_::find_msvc_12(tool, target)) + impl_::find_msvc_environment(tool, target, env_getter) + .or_else(|| impl_::find_msvc_15plus(tool, target, env_getter)) + .or_else(|| impl_::find_msvc_14(tool, target, env_getter)) + .or_else(|| impl_::find_msvc_12(tool, target, env_getter)) } /// A version of Visual Studio @@ -110,7 +169,12 @@ pub enum VsVers { /// /// This is used by the cmake crate to figure out the correct /// generator. +#[allow(clippy::disallowed_methods)] pub fn find_vs_version() -> Result { + fn has_msbuild_version(version: &str) -> bool { + impl_::has_msbuild_version(version, &StdEnvGetter) + } + match std::env::var("VisualStudioVersion") { Ok(version) => match &version[..] { "17.0" => Ok(VsVers::Vs17), @@ -131,15 +195,15 @@ pub fn find_vs_version() -> Result { _ => { // Check for the presence of a specific registry key // that indicates visual studio is installed. - if impl_::has_msbuild_version("17.0") { + if has_msbuild_version("17.0") { Ok(VsVers::Vs17) - } else if impl_::has_msbuild_version("16.0") { + } else if has_msbuild_version("16.0") { Ok(VsVers::Vs16) - } else if impl_::has_msbuild_version("15.0") { + } else if has_msbuild_version("15.0") { Ok(VsVers::Vs15) - } else if impl_::has_msbuild_version("14.0") { + } else if has_msbuild_version("14.0") { Ok(VsVers::Vs14) - } else if impl_::has_msbuild_version("12.0") { + } else if has_msbuild_version("12.0") { Ok(VsVers::Vs12) } else { Err("\n\n\ @@ -178,7 +242,7 @@ mod impl_ { use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Once; - use super::{TargetArch, MSVC_FAMILY}; + use super::{EnvGetter, TargetArch, MSVC_FAMILY}; use crate::Tool; struct MsvcTool { @@ -261,7 +325,7 @@ mod impl_ { } } - fn into_tool(self) -> Tool { + fn into_tool(self, env_getter: &dyn EnvGetter) -> Tool { let MsvcTool { tool, libs, @@ -269,17 +333,17 @@ mod impl_ { include, } = self; let mut tool = Tool::with_family(tool, MSVC_FAMILY); - add_env(&mut tool, "LIB", libs); - add_env(&mut tool, "PATH", path); - add_env(&mut tool, "INCLUDE", include); + add_env(&mut tool, "LIB", libs, env_getter); + add_env(&mut tool, "PATH", path, env_getter); + add_env(&mut tool, "INCLUDE", include, env_getter); tool } } /// Checks to see if the `VSCMD_ARG_TGT_ARCH` environment variable matches the /// given target's arch. Returns `None` if the variable does not exist. - fn is_vscmd_target(target: TargetArch<'_>) -> Option { - let vscmd_arch = env::var("VSCMD_ARG_TGT_ARCH").ok()?; + fn is_vscmd_target(target: TargetArch<'_>, env_getter: &dyn EnvGetter) -> Option { + let vscmd_arch = env_getter.get_env("VSCMD_ARG_TGT_ARCH")?; // Convert the Rust target arch to its VS arch equivalent. let arch = match target.into() { "x86_64" => "x64", @@ -289,23 +353,28 @@ mod impl_ { // An unrecognized arch. _ => return Some(false), }; - Some(vscmd_arch == arch) + Some(vscmd_arch.as_ref() == arch) } /// Attempt to find the tool using environment variables set by vcvars. - pub(super) fn find_msvc_environment(tool: &str, target: TargetArch<'_>) -> Option { + pub(super) fn find_msvc_environment( + tool: &str, + target: TargetArch<'_>, + env_getter: &dyn EnvGetter, + ) -> Option { // Early return if the environment doesn't contain a VC install. - env::var_os("VCINSTALLDIR")?; - let vs_install_dir: PathBuf = env::var_os("VSINSTALLDIR")?.into(); + env_getter.get_env("VCINSTALLDIR")?; + let vs_install_dir: PathBuf = env_getter.get_env("VSINSTALLDIR")?.into(); // If the vscmd target differs from the requested target then // attempt to get the tool using the VS install directory. - if is_vscmd_target(target) == Some(false) { + if is_vscmd_target(target, env_getter) == Some(false) { // We will only get here with versions 15+. - tool_from_vs15plus_instance(tool, target, &vs_install_dir) + tool_from_vs15plus_instance(tool, target, &vs_install_dir, env_getter) } else { // Fallback to simply using the current environment. - env::var_os("PATH") + env_getter + .get_env("PATH") .and_then(|path| { env::split_paths(&path) .map(|p| p.join(tool)) @@ -315,16 +384,17 @@ mod impl_ { } } - fn find_msbuild_vs17(target: TargetArch<'_>) -> Option { - find_tool_in_vs16plus_path(r"MSBuild\Current\Bin\MSBuild.exe", target, "17") + fn find_msbuild_vs17(target: TargetArch<'_>, env_getter: &dyn EnvGetter) -> Option { + find_tool_in_vs16plus_path(r"MSBuild\Current\Bin\MSBuild.exe", target, "17", env_getter) } #[allow(bare_trait_objects)] fn vs16plus_instances( target: TargetArch<'_>, version: &'static str, + env_getter: &dyn EnvGetter, ) -> Box> { - let instances = if let Some(instances) = vs15plus_instances(target) { + let instances = if let Some(instances) = vs15plus_instances(target, env_getter) { instances } else { return Box::new(iter::empty()); @@ -345,8 +415,9 @@ mod impl_ { tool: &str, target: TargetArch<'_>, version: &'static str, + env_getter: &dyn EnvGetter, ) -> Option { - vs16plus_instances(target, version) + vs16plus_instances(target, version, env_getter) .filter_map(|path| { let path = path.join(tool); if !path.is_file() { @@ -364,8 +435,8 @@ mod impl_ { .next() } - fn find_msbuild_vs16(target: TargetArch<'_>) -> Option { - find_tool_in_vs16plus_path(r"MSBuild\Current\Bin\MSBuild.exe", target, "16") + fn find_msbuild_vs16(target: TargetArch<'_>, env_getter: &dyn EnvGetter) -> Option { + find_tool_in_vs16plus_path(r"MSBuild\Current\Bin\MSBuild.exe", target, "16", env_getter) } // In MSVC 15 (2017) MS once again changed the scheme for locating @@ -380,8 +451,12 @@ mod impl_ { // // However, on ARM64 this method doesn't work because VS Installer fails to register COM component on ARM64. // Hence, as the last resort we try to use vswhere.exe to list available instances. - fn vs15plus_instances(target: TargetArch<'_>) -> Option { - vs15plus_instances_using_com().or_else(|| vs15plus_instances_using_vswhere(target)) + fn vs15plus_instances( + target: TargetArch<'_>, + env_getter: &dyn EnvGetter, + ) -> Option { + vs15plus_instances_using_com() + .or_else(|| vs15plus_instances_using_vswhere(target, env_getter)) } fn vs15plus_instances_using_com() -> Option { @@ -393,11 +468,15 @@ mod impl_ { Some(VsInstances::ComBased(enum_setup_instances)) } - fn vs15plus_instances_using_vswhere(target: TargetArch<'_>) -> Option { - let program_files_path: PathBuf = env::var("ProgramFiles(x86)") - .or_else(|_| env::var("ProgramFiles")) - .ok()? - .into(); + fn vs15plus_instances_using_vswhere( + target: TargetArch<'_>, + env_getter: &dyn EnvGetter, + ) -> Option { + let program_files_path = env_getter + .get_env("ProgramFiles(x86)") + .or_else(|| env_getter.get_env("ProgramFiles"))?; + + let program_files_path = Path::new(program_files_path.as_ref()); let vswhere_path = program_files_path.join(r"Microsoft Visual Studio\Installer\vswhere.exe"); @@ -443,13 +522,17 @@ mod impl_ { .collect() } - pub(super) fn find_msvc_15plus(tool: &str, target: TargetArch<'_>) -> Option { - let iter = vs15plus_instances(target)?; + pub(super) fn find_msvc_15plus( + tool: &str, + target: TargetArch<'_>, + env_getter: &dyn EnvGetter, + ) -> Option { + let iter = vs15plus_instances(target, env_getter)?; iter.into_iter() .filter_map(|instance| { let version = parse_version(&instance.installation_version()?)?; let instance_path = instance.installation_path()?; - let tool = tool_from_vs15plus_instance(tool, target, &instance_path)?; + let tool = tool_from_vs15plus_instance(tool, target, &instance_path, env_getter)?; Some((version, tool)) }) .max_by(|(a_version, _), (b_version, _)| a_version.cmp(b_version)) @@ -463,8 +546,12 @@ mod impl_ { // we keep the registry method as a fallback option. // // [more reliable]: https://github.com/rust-lang/cc-rs/pull/331 - fn find_tool_in_vs15_path(tool: &str, target: TargetArch<'_>) -> Option { - let mut path = match vs15plus_instances(target) { + fn find_tool_in_vs15_path( + tool: &str, + target: TargetArch<'_>, + env_getter: &dyn EnvGetter, + ) -> Option { + let mut path = match vs15plus_instances(target, env_getter) { Some(instances) => instances .into_iter() .filter_map(|instance| instance.installation_path()) @@ -498,9 +585,10 @@ mod impl_ { tool: &str, target: TargetArch<'_>, instance_path: &Path, + env_getter: &dyn EnvGetter, ) -> Option { let (root_path, bin_path, host_dylib_path, lib_path, alt_lib_path, include_path) = - vs15plus_vc_paths(target, instance_path)?; + vs15plus_vc_paths(target, instance_path, env_getter)?; let tool_path = bin_path.join(tool); if !tool_path.exists() { return None; @@ -520,14 +608,15 @@ mod impl_ { tool.include.push(atl_include_path); } - add_sdks(&mut tool, target)?; + add_sdks(&mut tool, target, env_getter)?; - Some(tool.into_tool()) + Some(tool.into_tool(env_getter)) } fn vs15plus_vc_paths( target: TargetArch<'_>, instance_path: &Path, + env_getter: &dyn EnvGetter, ) -> Option<(PathBuf, PathBuf, PathBuf, PathBuf, Option, PathBuf)> { let version = vs15plus_vc_read_version(instance_path)?; @@ -566,7 +655,7 @@ mod impl_ { // architecture, because it contains dlls like mspdb140.dll compiled for // the host architecture. let host_dylib_path = host_path.join(host.to_lowercase()); - let lib_fragment = if use_spectre_mitigated_libs() { + let lib_fragment = if use_spectre_mitigated_libs(env_getter) { r"lib\spectre" } else { "lib" @@ -621,8 +710,11 @@ mod impl_ { Some(version) } - fn use_spectre_mitigated_libs() -> bool { - env::var("VSCMD_ARG_VCVARS_SPECTRE").as_deref() == Ok("spectre") + fn use_spectre_mitigated_libs(env_getter: &dyn EnvGetter) -> bool { + env_getter + .get_env("VSCMD_ARG_VCVARS_SPECTRE") + .map(|env| env.as_ref() == "spectre") + .unwrap_or_default() } fn atl_paths(target: TargetArch<'_>, path: &Path) -> Option<(PathBuf, PathBuf)> { @@ -637,14 +729,22 @@ mod impl_ { // For MSVC 14 we need to find the Universal CRT as well as either // the Windows 10 SDK or Windows 8.1 SDK. - pub(super) fn find_msvc_14(tool: &str, target: TargetArch<'_>) -> Option { + pub(super) fn find_msvc_14( + tool: &str, + target: TargetArch<'_>, + env_getter: &dyn EnvGetter, + ) -> Option { let vcdir = get_vc_dir("14.0")?; let mut tool = get_tool(tool, &vcdir, target)?; - add_sdks(&mut tool, target)?; - Some(tool.into_tool()) + add_sdks(&mut tool, target, env_getter)?; + Some(tool.into_tool(env_getter)) } - fn add_sdks(tool: &mut MsvcTool, target: TargetArch<'_>) -> Option<()> { + fn add_sdks( + tool: &mut MsvcTool, + target: TargetArch<'_>, + env_getter: &dyn EnvGetter, + ) -> Option<()> { let sub = lib_subdir(target)?; let (ucrt, ucrt_version) = get_ucrt_dir()?; @@ -664,7 +764,7 @@ mod impl_ { let ucrt_lib = ucrt.join("lib").join(&ucrt_version); tool.libs.push(ucrt_lib.join("ucrt").join(sub)); - if let Some((sdk, version)) = get_sdk10_dir() { + if let Some((sdk, version)) = get_sdk10_dir(env_getter) { tool.path.push(sdk.join("bin").join(host)); let sdk_lib = sdk.join("lib").join(&version); tool.libs.push(sdk_lib.join("um").join(sub)); @@ -687,7 +787,11 @@ mod impl_ { } // For MSVC 12 we need to find the Windows 8.1 SDK. - pub(super) fn find_msvc_12(tool: &str, target: TargetArch<'_>) -> Option { + pub(super) fn find_msvc_12( + tool: &str, + target: TargetArch<'_>, + env_getter: &dyn EnvGetter, + ) -> Option { let vcdir = get_vc_dir("12.0")?; let mut tool = get_tool(tool, &vcdir, target)?; let sub = lib_subdir(target)?; @@ -699,11 +803,17 @@ mod impl_ { tool.include.push(sdk_include.join("shared")); tool.include.push(sdk_include.join("um")); tool.include.push(sdk_include.join("winrt")); - Some(tool.into_tool()) + Some(tool.into_tool(env_getter)) } - fn add_env(tool: &mut Tool, env: &str, paths: Vec) { - let prev = env::var_os(env).unwrap_or_default(); + fn add_env( + tool: &mut Tool, + env: &'static str, + paths: Vec, + env_getter: &dyn EnvGetter, + ) { + let prev = env_getter.get_env(env); + let prev = prev.as_ref().map(AsRef::as_ref).unwrap_or_default(); let prev = env::split_paths(&prev); let new = paths.into_iter().chain(prev); tool.env @@ -788,10 +898,18 @@ mod impl_ { // Before doing that, we check the "WindowsSdkDir" and "WindowsSDKVersion" // environment variables set by vcvars to use the environment sdk version // if one is already configured. - fn get_sdk10_dir() -> Option<(PathBuf, String)> { - if let (Ok(root), Ok(version)) = (env::var("WindowsSdkDir"), env::var("WindowsSDKVersion")) - { - return Some((root.into(), version.trim_end_matches('\\').to_string())); + fn get_sdk10_dir(env_getter: &dyn EnvGetter) -> Option<(PathBuf, String)> { + if let (Some(root), Some(version)) = ( + env_getter.get_env("WindowsSdkDir"), + env_getter + .get_env("WindowsSDKVersion") + .as_ref() + .and_then(|version| version.as_ref().to_str()), + ) { + return Some(( + PathBuf::from(root), + version.trim_end_matches('\\').to_string(), + )); } let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0"; @@ -933,22 +1051,23 @@ mod impl_ { max_key } - pub(super) fn has_msbuild_version(version: &str) -> bool { + #[inline(always)] + pub(super) fn has_msbuild_version(version: &str, env_getter: &dyn EnvGetter) -> bool { match version { "17.0" => { - find_msbuild_vs17(TargetArch("x86_64")).is_some() - || find_msbuild_vs17(TargetArch("i686")).is_some() - || find_msbuild_vs17(TargetArch("aarch64")).is_some() + find_msbuild_vs17(TargetArch("x86_64"), env_getter).is_some() + || find_msbuild_vs17(TargetArch("i686"), env_getter).is_some() + || find_msbuild_vs17(TargetArch("aarch64"), env_getter).is_some() } "16.0" => { - find_msbuild_vs16(TargetArch("x86_64")).is_some() - || find_msbuild_vs16(TargetArch("i686")).is_some() - || find_msbuild_vs16(TargetArch("aarch64")).is_some() + find_msbuild_vs16(TargetArch("x86_64"), env_getter).is_some() + || find_msbuild_vs16(TargetArch("i686"), env_getter).is_some() + || find_msbuild_vs16(TargetArch("aarch64"), env_getter).is_some() } "15.0" => { - find_msbuild_vs15(TargetArch("x86_64")).is_some() - || find_msbuild_vs15(TargetArch("i686")).is_some() - || find_msbuild_vs15(TargetArch("aarch64")).is_some() + find_msbuild_vs15(TargetArch("x86_64"), env_getter).is_some() + || find_msbuild_vs15(TargetArch("i686"), env_getter).is_some() + || find_msbuild_vs15(TargetArch("aarch64"), env_getter).is_some() } "12.0" | "14.0" => LOCAL_MACHINE .open(&OsString::from(format!( @@ -960,30 +1079,30 @@ mod impl_ { } } - pub(super) fn find_devenv(target: TargetArch<'_>) -> Option { - find_devenv_vs15(target) + pub(super) fn find_devenv(target: TargetArch<'_>, env_getter: &dyn EnvGetter) -> Option { + find_devenv_vs15(target, env_getter) } - fn find_devenv_vs15(target: TargetArch<'_>) -> Option { - find_tool_in_vs15_path(r"Common7\IDE\devenv.exe", target) + fn find_devenv_vs15(target: TargetArch<'_>, env_getter: &dyn EnvGetter) -> Option { + find_tool_in_vs15_path(r"Common7\IDE\devenv.exe", target, env_getter) } // see http://stackoverflow.com/questions/328017/path-to-msbuild - pub(super) fn find_msbuild(target: TargetArch<'_>) -> Option { + pub(super) fn find_msbuild(target: TargetArch<'_>, env_getter: &dyn EnvGetter) -> Option { // VS 15 (2017) changed how to locate msbuild - if let Some(r) = find_msbuild_vs17(target) { + if let Some(r) = find_msbuild_vs17(target, env_getter) { Some(r) - } else if let Some(r) = find_msbuild_vs16(target) { + } else if let Some(r) = find_msbuild_vs16(target, env_getter) { return Some(r); - } else if let Some(r) = find_msbuild_vs15(target) { + } else if let Some(r) = find_msbuild_vs15(target, env_getter) { return Some(r); } else { find_old_msbuild(target) } } - fn find_msbuild_vs15(target: TargetArch<'_>) -> Option { - find_tool_in_vs15_path(r"MSBuild\15.0\Bin\MSBuild.exe", target) + fn find_msbuild_vs15(target: TargetArch<'_>, env_getter: &dyn EnvGetter) -> Option { + find_tool_in_vs15_path(r"MSBuild\15.0\Bin\MSBuild.exe", target, env_getter) } fn find_old_msbuild(target: TargetArch<'_>) -> Option { @@ -1009,60 +1128,88 @@ mod impl_ { /// Non-Windows Implementation. #[cfg(not(windows))] mod impl_ { - use std::{env, ffi::OsString}; + use std::{env, ffi::OsStr}; - use super::{TargetArch, MSVC_FAMILY}; + use super::{EnvGetter, TargetArch, MSVC_FAMILY}; use crate::Tool; /// Finding msbuild.exe tool under unix system is not currently supported. /// Maybe can check it using an environment variable looks like `MSBUILD_BIN`. - pub(super) fn find_msbuild(_target: TargetArch<'_>) -> Option { + #[inline(always)] + pub(super) fn find_msbuild(_target: TargetArch<'_>, _: &dyn EnvGetter) -> Option { None } // Finding devenv.exe tool under unix system is not currently supported. // Maybe can check it using an environment variable looks like `DEVENV_BIN`. - pub(super) fn find_devenv(_target: TargetArch<'_>) -> Option { + #[inline(always)] + pub(super) fn find_devenv(_target: TargetArch<'_>, _: &dyn EnvGetter) -> Option { None } /// Attempt to find the tool using environment variables set by vcvars. - pub(super) fn find_msvc_environment(tool: &str, _target: TargetArch<'_>) -> Option { + pub(super) fn find_msvc_environment( + tool: &str, + _target: TargetArch<'_>, + env_getter: &dyn EnvGetter, + ) -> Option { // Early return if the environment doesn't contain a VC install. - let vc_install_dir = env::var_os("VCINSTALLDIR")?; - let vs_install_dir = env::var_os("VSINSTALLDIR")?; + let vc_install_dir = env_getter.get_env("VCINSTALLDIR")?; + let vs_install_dir = env_getter.get_env("VSINSTALLDIR")?; - let get_tool = |install_dir: OsString| { - env::split_paths(&install_dir) + let get_tool = |install_dir: &OsStr| { + env::split_paths(install_dir) .map(|p| p.join(tool)) .find(|p| p.exists()) .map(|path| Tool::with_family(path, MSVC_FAMILY)) }; // Take the path of tool for the vc install directory. - get_tool(vc_install_dir) + get_tool(vc_install_dir.as_ref()) // Take the path of tool for the vs install directory. - .or_else(|| get_tool(vs_install_dir)) + .or_else(|| get_tool(vs_install_dir.as_ref())) // Take the path of tool for the current path environment. - .or_else(|| env::var_os("PATH").and_then(get_tool)) + .or_else(|| { + env_getter + .get_env("PATH") + .as_ref() + .map(|path| path.as_ref()) + .and_then(get_tool) + }) } - pub(super) fn find_msvc_15plus(_tool: &str, _target: TargetArch<'_>) -> Option { + #[inline(always)] + pub(super) fn find_msvc_15plus( + _tool: &str, + _target: TargetArch<'_>, + _: &dyn EnvGetter, + ) -> Option { None } // For MSVC 14 we need to find the Universal CRT as well as either // the Windows 10 SDK or Windows 8.1 SDK. - pub(super) fn find_msvc_14(_tool: &str, _target: TargetArch<'_>) -> Option { + #[inline(always)] + pub(super) fn find_msvc_14( + _tool: &str, + _target: TargetArch<'_>, + _: &dyn EnvGetter, + ) -> Option { None } // For MSVC 12 we need to find the Windows 8.1 SDK. - pub(super) fn find_msvc_12(_tool: &str, _target: TargetArch<'_>) -> Option { + #[inline(always)] + pub(super) fn find_msvc_12( + _tool: &str, + _target: TargetArch<'_>, + _: &dyn EnvGetter, + ) -> Option { None } - pub(super) fn has_msbuild_version(version: &str) -> bool { + #[inline(always)] + pub(super) fn has_msbuild_version(version: &str, _: &dyn EnvGetter) -> bool { match version { "17.0" => false, "16.0" => false, diff --git a/tests/support/mod.rs b/tests/support/mod.rs index 4bdef027..5e87001e 100644 --- a/tests/support/mod.rs +++ b/tests/support/mod.rs @@ -1,4 +1,5 @@ #![allow(dead_code)] +#![allow(clippy::disallowed_methods)] use std::env; use std::ffi::{OsStr, OsString}; diff --git a/tests/test.rs b/tests/test.rs index 8fc8da64..4c070889 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,3 +1,5 @@ +#![allow(clippy::disallowed_methods)] + use crate::support::Test; mod support; @@ -575,8 +577,8 @@ fn clang_apple_tvos() { let test = Test::clang(); test.gcc() .__set_env("TVOS_DEPLOYMENT_TARGET", "9.0") - .target(&target) - .host(&target) + .target(target) + .host(target) .file("foo.c") .compile("foo"); @@ -628,8 +630,8 @@ fn clang_apple_tvsimulator() { let test = Test::clang(); test.gcc() .__set_env("TVOS_DEPLOYMENT_TARGET", "9.0") - .target(&target) - .host(&target) + .target(target) + .host(target) .file("foo.c") .compile("foo");