diff --git a/src/lib.rs b/src/lib.rs index 5be21ee3f..5c7b37e50 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3559,7 +3559,6 @@ impl Tool { Self::with_features(path, clang_driver, false, cargo_output) } - #[cfg(windows)] /// Explicitly set the `ToolFamily`, skipping name-based detection. fn with_family(path: PathBuf, family: ToolFamily) -> Self { Self { diff --git a/src/windows_registry.rs b/src/windows_registry.rs index cf1c2edb7..694be5549 100644 --- a/src/windows_registry.rs +++ b/src/windows_registry.rs @@ -8,22 +8,39 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! A helper module to probe the Windows Registry when looking for -//! windows-specific tools. +//! A helper module to looking for windows-specific tools: +//! 1. On Windows host, probe the Windows Registry if needed; +//! 2. On non-Windows host, check specified environment variables. +#![allow(clippy::upper_case_acronyms)] #![allow(clippy::upper_case_acronyms)] use std::process::Command; use crate::Tool; -#[cfg(windows)] use crate::ToolFamily; -#[cfg(windows)] const MSVC_FAMILY: ToolFamily = ToolFamily::Msvc { clang_cl: false }; -/// Attempts to find a tool within an MSVC installation using the Windows -/// registry as a point to search from. +#[derive(Copy, Clone)] +struct TargetArch<'a>(pub &'a str); + +impl PartialEq<&str> for TargetArch<'_> { + fn eq(&self, other: &&str) -> bool { + self.0 == *other + } +} + +impl<'a> From> for &'a str { + fn from(target: TargetArch<'a>) -> Self { + target.0 + } +} + +/// Attempts to find a tool within an MSVC installation: +/// 1. On Windows host, using the Windows registry as a point to search from; +/// 2. On non-Windows host, using related environment variables to search from. +/// /// /// The `target` argument is the target that the tool should work for (e.g. /// compile or link for) and the `tool` argument is the tool to find (e.g. @@ -41,13 +58,6 @@ pub fn find(target: &str, tool: &str) -> Option { /// Similar to the `find` function above, this function will attempt the same /// operation (finding a MSVC tool in a local install) but instead returns a /// `Tool` which may be introspected. -#[cfg(not(windows))] -pub fn find_tool(_target: &str, _tool: &str) -> Option { - None -} - -/// Documented above. -#[cfg(windows)] pub fn find_tool(target: &str, tool: &str) -> Option { // This logic is all tailored for MSVC, if we're not that then bail out // early. @@ -56,15 +66,16 @@ pub fn find_tool(target: &str, tool: &str) -> Option { } // Split the target to get the arch. - let target = impl_::TargetArch(target.split_once('-')?.0); + let target = TargetArch(target.split_once('-')?.0); // Looks like msbuild isn't located in the same location as other tools like - // cl.exe and lib.exe. To handle this we probe for it manually with - // dedicated registry keys. + // cl.exe and lib.exe. if tool.contains("msbuild") { return impl_::find_msbuild(target); } + // 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); } @@ -103,17 +114,8 @@ pub enum VsVers { /// /// This is used by the cmake crate to figure out the correct /// generator. -#[cfg(not(windows))] pub fn find_vs_version() -> Result { - Err("not windows".to_string()) -} - -/// Documented above -#[cfg(windows)] -pub fn find_vs_version() -> Result { - use std::env; - - match env::var("VisualStudioVersion") { + match std::env::var("VisualStudioVersion") { Ok(version) => match &version[..] { "17.0" => Ok(VsVers::Vs17), "16.0" => Ok(VsVers::Vs16), @@ -157,6 +159,7 @@ pub fn find_vs_version() -> Result { } } +/// Windows Implementation. #[cfg(windows)] mod impl_ { use crate::com; @@ -174,24 +177,9 @@ mod impl_ { use std::process::Command; use std::str::FromStr; - use super::MSVC_FAMILY; + use super::{TargetArch, MSVC_FAMILY}; use crate::Tool; - #[derive(Copy, Clone)] - pub struct TargetArch<'a>(pub &'a str); - - impl PartialEq<&str> for TargetArch<'_> { - fn eq(&self, other: &&str) -> bool { - self.0 == *other - } - } - - impl<'a> From> for &'a str { - fn from(target: TargetArch<'a>) -> Self { - target.0 - } - } - struct MsvcTool { tool: PathBuf, libs: Vec, @@ -242,7 +230,7 @@ mod impl_ { } /// Attempt to find the tool using environment variables set by vcvars. - pub fn find_msvc_environment(tool: &str, target: TargetArch<'_>) -> Option { + pub(super) fn find_msvc_environment(tool: &str, target: TargetArch<'_>) -> Option { // Early return if the environment doesn't contain a VC install. if env::var_os("VCINSTALLDIR").is_none() { return None; @@ -394,7 +382,7 @@ mod impl_ { .collect() } - pub fn find_msvc_15plus(tool: &str, target: TargetArch<'_>) -> Option { + pub(super) fn find_msvc_15plus(tool: &str, target: TargetArch<'_>) -> Option { let iter = vs15plus_instances(target)?; iter.into_iter() .filter_map(|instance| { @@ -565,7 +553,7 @@ 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 fn find_msvc_14(tool: &str, target: TargetArch<'_>) -> Option { + pub(super) fn find_msvc_14(tool: &str, target: TargetArch<'_>) -> Option { let vcdir = get_vc_dir("14.0")?; let mut tool = get_tool(tool, &vcdir, target)?; add_sdks(&mut tool, target)?; @@ -615,7 +603,7 @@ mod impl_ { } // For MSVC 12 we need to find the Windows 8.1 SDK. - pub fn find_msvc_12(tool: &str, target: TargetArch<'_>) -> Option { + pub(super) fn find_msvc_12(tool: &str, target: TargetArch<'_>) -> Option { let vcdir = get_vc_dir("12.0")?; let mut tool = get_tool(tool, &vcdir, target)?; let sub = lib_subdir(target)?; @@ -631,7 +619,7 @@ mod impl_ { } // For MSVC 11 we need to find the Windows 8 SDK. - pub fn find_msvc_11(tool: &str, target: TargetArch<'_>) -> Option { + pub(super) fn find_msvc_11(tool: &str, target: TargetArch<'_>) -> Option { let vcdir = get_vc_dir("11.0")?; let mut tool = get_tool(tool, &vcdir, target)?; let sub = lib_subdir(target)?; @@ -885,7 +873,7 @@ mod impl_ { max_key } - pub fn has_msbuild_version(version: &str) -> bool { + pub(super) fn has_msbuild_version(version: &str) -> bool { match version { "17.0" => { find_msbuild_vs17(TargetArch("x86_64")).is_some() @@ -912,7 +900,8 @@ mod impl_ { } } - pub fn find_devenv(target: TargetArch<'_>) -> Option { + // To find devenv we probe for it manually with dedicated registry keys. + pub(super) fn find_devenv(target: TargetArch<'_>) -> Option { find_devenv_vs15(target) } @@ -920,8 +909,9 @@ mod impl_ { find_tool_in_vs15_path(r"Common7\IDE\devenv.exe", target) } + // To find msbuild we probe for it manually with dedicated registry keys. // see http://stackoverflow.com/questions/328017/path-to-msbuild - pub fn find_msbuild(target: TargetArch<'_>) -> Option { + pub(super) fn find_msbuild(target: TargetArch<'_>) -> Option { // VS 15 (2017) changed how to locate msbuild if let Some(r) = find_msbuild_vs17(target) { Some(r) @@ -957,3 +947,73 @@ mod impl_ { }) } } + +/// Non-Windows Implementation. +#[cfg(not(windows))] +mod impl_ { + use std::{env, ffi::OsString}; + + use super::{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 { + 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 { + None + } + + /// Attempt to find the tool using environment variables set by vcvars. + pub(super) fn find_msvc_environment(tool: &str, _target: TargetArch<'_>) -> 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")?; + + // Should we take the path of tool for the v[c|s] install dir? + // Both `VCINSTALLDIR` / `VSINSTALLDIR` are unused currently. + + // Fallback to simply using the current environment. + env::var_os("PATH") + .and_then(|path: OsString| { + env::split_paths(&path) + .map(|p| p.join(tool)) + .find(|p| p.exists()) + }) + .map(|path| Tool::with_family(path.into(), MSVC_FAMILY)) + } + + pub(super) fn find_msvc_15plus(_tool: &str, _target: TargetArch<'_>) -> 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 { + None + } + + // For MSVC 12 we need to find the Windows 8.1 SDK. + pub(super) fn find_msvc_12(_tool: &str, _target: TargetArch<'_>) -> Option { + None + } + + // For MSVC 11 we need to find the Windows 8 SDK. + pub(super) fn find_msvc_11(_tool: &str, _target: TargetArch<'_>) -> Option { + None + } + + pub(super) fn has_msbuild_version(version: &str) -> bool { + match version { + "17.0" => false, + "16.0" => false, + "15.0" => false, + "12.0" | "14.0" => false, + _ => false, + } + } +}