Skip to content

Commit 61b4713

Browse files
caviviecavivie
cavivie
authored andcommitted
Support finding windows tools on non-Windows host
1 parent 8cf5455 commit 61b4713

File tree

2 files changed

+109
-51
lines changed

2 files changed

+109
-51
lines changed

src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3559,7 +3559,6 @@ impl Tool {
35593559
Self::with_features(path, clang_driver, false, cargo_output)
35603560
}
35613561

3562-
#[cfg(windows)]
35633562
/// Explicitly set the `ToolFamily`, skipping name-based detection.
35643563
fn with_family(path: PathBuf, family: ToolFamily) -> Self {
35653564
Self {

src/windows_registry.rs

Lines changed: 109 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,38 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
//! A helper module to probe the Windows Registry when looking for
12-
//! windows-specific tools.
11+
//! A helper module to looking for windows-specific tools:
12+
//! 1. On Windows host, probe the Windows Registry if needed;
13+
//! 2. On non-Windows host, check specified environment variables.
1314
1415
#![allow(clippy::upper_case_acronyms)]
1516

1617
use std::process::Command;
1718

1819
use crate::Tool;
19-
#[cfg(windows)]
2020
use crate::ToolFamily;
2121

22-
#[cfg(windows)]
2322
const MSVC_FAMILY: ToolFamily = ToolFamily::Msvc { clang_cl: false };
2423

25-
/// Attempts to find a tool within an MSVC installation using the Windows
26-
/// registry as a point to search from.
24+
#[derive(Copy, Clone)]
25+
struct TargetArch<'a>(pub &'a str);
26+
27+
impl PartialEq<&str> for TargetArch<'_> {
28+
fn eq(&self, other: &&str) -> bool {
29+
self.0 == *other
30+
}
31+
}
32+
33+
impl<'a> From<TargetArch<'a>> for &'a str {
34+
fn from(target: TargetArch<'a>) -> Self {
35+
target.0
36+
}
37+
}
38+
39+
/// Attempts to find a tool within an MSVC installation:
40+
/// 1. On Windows host, using the Windows registry as a point to search from;
41+
/// 2. On non-Windows host, using related environment variables to search from.
42+
///
2743
///
2844
/// The `target` argument is the target that the tool should work for (e.g.
2945
/// compile or link for) and the `tool` argument is the tool to find (e.g.
@@ -41,13 +57,6 @@ pub fn find(target: &str, tool: &str) -> Option<Command> {
4157
/// Similar to the `find` function above, this function will attempt the same
4258
/// operation (finding a MSVC tool in a local install) but instead returns a
4359
/// `Tool` which may be introspected.
44-
#[cfg(not(windows))]
45-
pub fn find_tool(_target: &str, _tool: &str) -> Option<Tool> {
46-
None
47-
}
48-
49-
/// Documented above.
50-
#[cfg(windows)]
5160
pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
5261
// This logic is all tailored for MSVC, if we're not that then bail out
5362
// early.
@@ -56,15 +65,16 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
5665
}
5766

5867
// Split the target to get the arch.
59-
let target = impl_::TargetArch(target.split_once('-')?.0);
68+
let target = TargetArch(target.split_once('-')?.0);
6069

6170
// Looks like msbuild isn't located in the same location as other tools like
62-
// cl.exe and lib.exe. To handle this we probe for it manually with
63-
// dedicated registry keys.
71+
// cl.exe and lib.exe.
6472
if tool.contains("msbuild") {
6573
return impl_::find_msbuild(target);
6674
}
6775

76+
// Looks like devenv isn't located in the same location as other tools like
77+
// cl.exe and lib.exe.
6878
if tool.contains("devenv") {
6979
return impl_::find_devenv(target);
7080
}
@@ -103,17 +113,8 @@ pub enum VsVers {
103113
///
104114
/// This is used by the cmake crate to figure out the correct
105115
/// generator.
106-
#[cfg(not(windows))]
107116
pub fn find_vs_version() -> Result<VsVers, String> {
108-
Err("not windows".to_string())
109-
}
110-
111-
/// Documented above
112-
#[cfg(windows)]
113-
pub fn find_vs_version() -> Result<VsVers, String> {
114-
use std::env;
115-
116-
match env::var("VisualStudioVersion") {
117+
match std::env::var("VisualStudioVersion") {
117118
Ok(version) => match &version[..] {
118119
"17.0" => Ok(VsVers::Vs17),
119120
"16.0" => Ok(VsVers::Vs16),
@@ -157,6 +158,7 @@ pub fn find_vs_version() -> Result<VsVers, String> {
157158
}
158159
}
159160

161+
/// Windows Implementation.
160162
#[cfg(windows)]
161163
mod impl_ {
162164
use crate::com;
@@ -174,24 +176,9 @@ mod impl_ {
174176
use std::process::Command;
175177
use std::str::FromStr;
176178

177-
use super::MSVC_FAMILY;
179+
use super::{TargetArch, MSVC_FAMILY};
178180
use crate::Tool;
179181

180-
#[derive(Copy, Clone)]
181-
pub struct TargetArch<'a>(pub &'a str);
182-
183-
impl PartialEq<&str> for TargetArch<'_> {
184-
fn eq(&self, other: &&str) -> bool {
185-
self.0 == *other
186-
}
187-
}
188-
189-
impl<'a> From<TargetArch<'a>> for &'a str {
190-
fn from(target: TargetArch<'a>) -> Self {
191-
target.0
192-
}
193-
}
194-
195182
struct MsvcTool {
196183
tool: PathBuf,
197184
libs: Vec<PathBuf>,
@@ -242,7 +229,7 @@ mod impl_ {
242229
}
243230

244231
/// Attempt to find the tool using environment variables set by vcvars.
245-
pub fn find_msvc_environment(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
232+
pub(super) fn find_msvc_environment(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
246233
// Early return if the environment doesn't contain a VC install.
247234
if env::var_os("VCINSTALLDIR").is_none() {
248235
return None;
@@ -394,7 +381,7 @@ mod impl_ {
394381
.collect()
395382
}
396383

397-
pub fn find_msvc_15plus(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
384+
pub(super) fn find_msvc_15plus(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
398385
let iter = vs15plus_instances(target)?;
399386
iter.into_iter()
400387
.filter_map(|instance| {
@@ -565,7 +552,7 @@ mod impl_ {
565552

566553
// For MSVC 14 we need to find the Universal CRT as well as either
567554
// the Windows 10 SDK or Windows 8.1 SDK.
568-
pub fn find_msvc_14(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
555+
pub(super) fn find_msvc_14(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
569556
let vcdir = get_vc_dir("14.0")?;
570557
let mut tool = get_tool(tool, &vcdir, target)?;
571558
add_sdks(&mut tool, target)?;
@@ -615,7 +602,7 @@ mod impl_ {
615602
}
616603

617604
// For MSVC 12 we need to find the Windows 8.1 SDK.
618-
pub fn find_msvc_12(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
605+
pub(super) fn find_msvc_12(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
619606
let vcdir = get_vc_dir("12.0")?;
620607
let mut tool = get_tool(tool, &vcdir, target)?;
621608
let sub = lib_subdir(target)?;
@@ -631,7 +618,7 @@ mod impl_ {
631618
}
632619

633620
// For MSVC 11 we need to find the Windows 8 SDK.
634-
pub fn find_msvc_11(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
621+
pub(super) fn find_msvc_11(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
635622
let vcdir = get_vc_dir("11.0")?;
636623
let mut tool = get_tool(tool, &vcdir, target)?;
637624
let sub = lib_subdir(target)?;
@@ -885,7 +872,7 @@ mod impl_ {
885872
max_key
886873
}
887874

888-
pub fn has_msbuild_version(version: &str) -> bool {
875+
pub(super) fn has_msbuild_version(version: &str) -> bool {
889876
match version {
890877
"17.0" => {
891878
find_msbuild_vs17(TargetArch("x86_64")).is_some()
@@ -912,16 +899,18 @@ mod impl_ {
912899
}
913900
}
914901

915-
pub fn find_devenv(target: TargetArch<'_>) -> Option<Tool> {
902+
// To find devenv we probe for it manually with dedicated registry keys.
903+
pub(super) fn find_devenv(target: TargetArch<'_>) -> Option<Tool> {
916904
find_devenv_vs15(target)
917905
}
918906

919907
fn find_devenv_vs15(target: TargetArch<'_>) -> Option<Tool> {
920908
find_tool_in_vs15_path(r"Common7\IDE\devenv.exe", target)
921909
}
922910

911+
// To find msbuild we probe for it manually with dedicated registry keys.
923912
// see http://stackoverflow.com/questions/328017/path-to-msbuild
924-
pub fn find_msbuild(target: TargetArch<'_>) -> Option<Tool> {
913+
pub(super) fn find_msbuild(target: TargetArch<'_>) -> Option<Tool> {
925914
// VS 15 (2017) changed how to locate msbuild
926915
if let Some(r) = find_msbuild_vs17(target) {
927916
Some(r)
@@ -957,3 +946,73 @@ mod impl_ {
957946
})
958947
}
959948
}
949+
950+
/// Non-Windows Implementation.
951+
#[cfg(not(windows))]
952+
mod impl_ {
953+
use std::{env, ffi::OsString};
954+
955+
use super::{TargetArch, MSVC_FAMILY};
956+
use crate::Tool;
957+
958+
/// Finding msbuild.exe tool under unix system is not currently supported.
959+
/// Maybe can check it using an environment variable looks like `MSBUILD_BIN`.
960+
pub(super) fn find_msbuild(_target: TargetArch<'_>) -> Option<Tool> {
961+
None
962+
}
963+
964+
// Finding devenv.exe tool under unix system is not currently supported.
965+
// Maybe can check it using an environment variable looks like `DEVENV_BIN`.
966+
pub(super) fn find_devenv(_target: TargetArch<'_>) -> Option<Tool> {
967+
None
968+
}
969+
970+
/// Attempt to find the tool using environment variables set by vcvars.
971+
pub(super) fn find_msvc_environment(tool: &str, _target: TargetArch<'_>) -> Option<Tool> {
972+
// Early return if the environment doesn't contain a VC install.
973+
let _vc_install_dir = env::var_os("VCINSTALLDIR")?;
974+
let _vs_install_dir = env::var_os("VSINSTALLDIR")?;
975+
976+
// Should we take the path of tool for the v[c|s] install dir?
977+
// Both `VCINSTALLDIR` / `VSINSTALLDIR` are unused currently.
978+
979+
// Fallback to simply using the current environment.
980+
env::var_os("PATH")
981+
.and_then(|path: OsString| {
982+
env::split_paths(&path)
983+
.map(|p| p.join(tool))
984+
.find(|p| p.exists())
985+
})
986+
.map(|path| Tool::with_family(path.into(), MSVC_FAMILY))
987+
}
988+
989+
pub(super) fn find_msvc_15plus(_tool: &str, _target: TargetArch<'_>) -> Option<Tool> {
990+
None
991+
}
992+
993+
// For MSVC 14 we need to find the Universal CRT as well as either
994+
// the Windows 10 SDK or Windows 8.1 SDK.
995+
pub(super) fn find_msvc_14(_tool: &str, _target: TargetArch<'_>) -> Option<Tool> {
996+
None
997+
}
998+
999+
// For MSVC 12 we need to find the Windows 8.1 SDK.
1000+
pub(super) fn find_msvc_12(_tool: &str, _target: TargetArch<'_>) -> Option<Tool> {
1001+
None
1002+
}
1003+
1004+
// For MSVC 11 we need to find the Windows 8 SDK.
1005+
pub(super) fn find_msvc_11(_tool: &str, _target: TargetArch<'_>) -> Option<Tool> {
1006+
None
1007+
}
1008+
1009+
pub(super) fn has_msbuild_version(version: &str) -> bool {
1010+
match version {
1011+
"17.0" => false,
1012+
"16.0" => false,
1013+
"15.0" => false,
1014+
"12.0" | "14.0" => false,
1015+
_ => false,
1016+
}
1017+
}
1018+
}

0 commit comments

Comments
 (0)