From 419a37eb93957ae4d050d134d8170e6f0e5e5e7c Mon Sep 17 00:00:00 2001 From: cavivie Date: Tue, 28 Nov 2023 16:03:28 +0800 Subject: [PATCH] Support finding windows tools on non-Windows host --- cc-test/build.rs | 6 +- src/lib.rs | 9 +- ...{windows_registry.rs => windows_helper.rs} | 89 +++++++++++++++---- 3 files changed, 81 insertions(+), 23 deletions(-) rename src/{windows_registry.rs => windows_helper.rs} (92%) diff --git a/cc-test/build.rs b/cc-test/build.rs index 695c75473..8303749be 100644 --- a/cc-test/build.rs +++ b/cc-test/build.rs @@ -57,14 +57,14 @@ fn main() { cc::Build::new().file("src/windows.c").compile("windows"); } - // Test that the `windows_registry` module will set PATH by looking for + // Test that the `windows_helper` module will set PATH by looking for // nmake which runs vanilla cl, and then also test it after we remove all // the relevant env vars from our own process. if target.contains("msvc") { let out = out.join("tmp"); fs::create_dir(&out).unwrap(); println!("nmake 1"); - let status = cc::windows_registry::find(&target, "nmake.exe") + let status = cc::windows_helper::find(&target, "nmake.exe") .unwrap() .env_remove("MAKEFLAGS") .arg("/fsrc/NMakefile") @@ -81,7 +81,7 @@ fn main() { env::remove_var("INCLUDE"); env::remove_var("LIB"); println!("nmake 2"); - let status = cc::windows_registry::find(&target, "nmake.exe") + let status = cc::windows_helper::find(&target, "nmake.exe") .unwrap() .env_remove("MAKEFLAGS") .arg("/fsrc/NMakefile") diff --git a/src/lib.rs b/src/lib.rs index 0123bb16c..cf5c57481 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -87,7 +87,7 @@ mod vs_instances; #[cfg(windows)] mod windows_sys; -pub mod windows_registry; +pub mod windows_helper; /// A builder for compilation of a native library. /// @@ -2187,7 +2187,7 @@ impl Build { } else { "ml.exe" }; - let mut cmd = windows_registry::find(&target, tool).unwrap_or_else(|| self.cmd(tool)); + let mut cmd = windows_helper::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); @@ -2540,7 +2540,7 @@ impl Build { traditional }; - let cl_exe = windows_registry::find_tool(&target, "cl.exe"); + let cl_exe = windows_helper::find_tool(&target, "cl.exe"); let tool_opt: Option = self .env_tool(env) @@ -3008,7 +3008,7 @@ impl Build { if lib.is_empty() { name = String::from("lib.exe"); - match windows_registry::find(&target, "lib.exe") { + match windows_helper::find(&target, "lib.exe") { Some(t) => t, None => self.cmd("lib.exe"), } @@ -3543,7 +3543,6 @@ impl Tool { Self::with_features(path, clang_driver, false) } - #[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_helper.rs similarity index 92% rename from src/windows_registry.rs rename to src/windows_helper.rs index 00040289c..8d39e8001 100644 --- a/src/windows_registry.rs +++ b/src/windows_helper.rs @@ -8,20 +8,21 @@ // 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. 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. +/// 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. @@ -39,13 +40,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. @@ -54,12 +48,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. 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); } @@ -152,6 +147,7 @@ pub fn find_vs_version() -> Result { } } +/// Windows Implementation. #[cfg(windows)] mod impl_ { use crate::com; @@ -882,6 +878,7 @@ mod impl_ { } } + // To find devenv we probe for it manually with dedicated registry keys. pub fn find_devenv(target: &str) -> Option { find_devenv_vs15(&target) } @@ -890,6 +887,7 @@ 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: &str) -> Option { // VS 15 (2017) changed how to locate msbuild @@ -927,3 +925,64 @@ mod impl_ { }) } } + +/// Non-Windows Implementation. +#[cfg(not(windows))] +mod impl_ { + use std::{env, ffi::OsString}; + + use super::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 fn find_msbuild(_target: &str) -> 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 fn find_devenv(_target: &str) -> Option { + None + } + + /// Attempt to find the tool using environment variables set by vcvars. + pub fn find_msvc_environment(tool: &str, _target: &str) -> 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 search = |path: OsString| { + env::split_paths(&path) + .map(|p| p.join(tool)) + .find(|p| p.exists()) + }; + + search(vs_install_dir) + .or_else(|| { + // Fallback to simply using the current environment. + env::var_os("PATH").and_then(search) + }) + .map(|path| Tool::with_family(path.into(), MSVC_FAMILY)) + } + + pub fn find_msvc_15plus(_tool: &str, _target: &str) -> 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 fn find_msvc_14(_tool: &str, _target: &str) -> Option { + None + } + + // For MSVC 12 we need to find the Windows 8.1 SDK. + pub fn find_msvc_12(_tool: &str, _target: &str) -> Option { + None + } + + // For MSVC 11 we need to find the Windows 8 SDK. + pub fn find_msvc_11(_tool: &str, _target: &str) -> Option { + None + } +}