From 9976236f86e57970816c36b9abda63231c7ce4d4 Mon Sep 17 00:00:00 2001 From: cavivie Date: Sun, 25 Feb 2024 16:06:33 +0800 Subject: [PATCH] Also support finding Windows tools on non-Windows host --- src/tool.rs | 1 - src/windows/find_tools.rs | 151 ++++++++++++++++++++++++++------------ 2 files changed, 103 insertions(+), 49 deletions(-) diff --git a/src/tool.rs b/src/tool.rs index 39131eaef..a193a90ff 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -53,7 +53,6 @@ impl Tool { ) } - #[cfg(windows)] /// Explicitly set the `ToolFamily`, skipping name-based detection. pub(crate) fn with_family(path: PathBuf, family: ToolFamily) -> Self { Self { diff --git a/src/windows/find_tools.rs b/src/windows/find_tools.rs index 9c6511555..dedb82d97 100644 --- a/src/windows/find_tools.rs +++ b/src/windows/find_tools.rs @@ -8,20 +8,34 @@ // 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)] use std::process::Command; use crate::Tool; -#[cfg(windows)] use crate::ToolFamily; -#[cfg(windows)] const MSVC_FAMILY: ToolFamily = ToolFamily::Msvc { clang_cl: false }; +#[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 using the Windows /// registry as a point to search from. /// @@ -41,13 +55,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 +63,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 +111,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 +156,7 @@ pub fn find_vs_version() -> Result { } } +/// Windows Implementation. #[cfg(windows)] mod impl_ { use crate::windows::com; @@ -180,24 +180,9 @@ mod impl_ { use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Once; - 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, @@ -312,7 +297,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; @@ -464,7 +449,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| { @@ -649,7 +634,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)?; @@ -699,7 +684,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)?; @@ -715,7 +700,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)?; @@ -969,7 +954,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() @@ -996,7 +981,7 @@ mod impl_ { } } - pub fn find_devenv(target: TargetArch<'_>) -> Option { + pub(super) fn find_devenv(target: TargetArch<'_>) -> Option { find_devenv_vs15(target) } @@ -1005,7 +990,7 @@ mod impl_ { } // 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) @@ -1041,3 +1026,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, + } + } +}