Skip to content

Commit 2f587f5

Browse files
authored
Also support finding Windows tools on non-Windows host (#907)
1 parent 59581e5 commit 2f587f5

File tree

2 files changed

+105
-49
lines changed

2 files changed

+105
-49
lines changed

src/tool.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ impl Tool {
5353
)
5454
}
5555

56-
#[cfg(windows)]
5756
/// Explicitly set the `ToolFamily`, skipping name-based detection.
5857
pub(crate) fn with_family(path: PathBuf, family: ToolFamily) -> Self {
5958
Self {

src/windows/find_tools.rs

Lines changed: 105 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,34 @@
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

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+
2539
/// Attempts to find a tool within an MSVC installation using the Windows
2640
/// registry as a point to search from.
2741
///
@@ -41,13 +55,6 @@ pub fn find(target: &str, tool: &str) -> Option<Command> {
4155
/// Similar to the `find` function above, this function will attempt the same
4256
/// operation (finding a MSVC tool in a local install) but instead returns a
4357
/// `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)]
5158
pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
5259
// This logic is all tailored for MSVC, if we're not that then bail out
5360
// early.
@@ -56,15 +63,16 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
5663
}
5764

5865
// Split the target to get the arch.
59-
let target = impl_::TargetArch(target.split_once('-')?.0);
66+
let target = TargetArch(target.split_once('-')?.0);
6067

6168
// 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.
69+
// cl.exe and lib.exe.
6470
if tool.contains("msbuild") {
6571
return impl_::find_msbuild(target);
6672
}
6773

74+
// Looks like devenv isn't located in the same location as other tools like
75+
// cl.exe and lib.exe.
6876
if tool.contains("devenv") {
6977
return impl_::find_devenv(target);
7078
}
@@ -103,17 +111,8 @@ pub enum VsVers {
103111
///
104112
/// This is used by the cmake crate to figure out the correct
105113
/// generator.
106-
#[cfg(not(windows))]
107-
pub fn find_vs_version() -> Result<VsVers, String> {
108-
Err("not windows".to_string())
109-
}
110-
111-
/// Documented above
112-
#[cfg(windows)]
113114
pub fn find_vs_version() -> Result<VsVers, String> {
114-
use std::env;
115-
116-
match env::var("VisualStudioVersion") {
115+
match std::env::var("VisualStudioVersion") {
117116
Ok(version) => match &version[..] {
118117
"17.0" => Ok(VsVers::Vs17),
119118
"16.0" => Ok(VsVers::Vs16),
@@ -157,6 +156,7 @@ pub fn find_vs_version() -> Result<VsVers, String> {
157156
}
158157
}
159158

159+
/// Windows Implementation.
160160
#[cfg(windows)]
161161
mod impl_ {
162162
use crate::windows::com;
@@ -180,24 +180,9 @@ mod impl_ {
180180
use std::sync::atomic::{AtomicBool, Ordering};
181181
use std::sync::Once;
182182

183-
use super::MSVC_FAMILY;
183+
use super::{TargetArch, MSVC_FAMILY};
184184
use crate::Tool;
185185

186-
#[derive(Copy, Clone)]
187-
pub struct TargetArch<'a>(pub &'a str);
188-
189-
impl PartialEq<&str> for TargetArch<'_> {
190-
fn eq(&self, other: &&str) -> bool {
191-
self.0 == *other
192-
}
193-
}
194-
195-
impl<'a> From<TargetArch<'a>> for &'a str {
196-
fn from(target: TargetArch<'a>) -> Self {
197-
target.0
198-
}
199-
}
200-
201186
struct MsvcTool {
202187
tool: PathBuf,
203188
libs: Vec<PathBuf>,
@@ -312,7 +297,7 @@ mod impl_ {
312297
}
313298

314299
/// Attempt to find the tool using environment variables set by vcvars.
315-
pub fn find_msvc_environment(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
300+
pub(super) fn find_msvc_environment(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
316301
// Early return if the environment doesn't contain a VC install.
317302
if env::var_os("VCINSTALLDIR").is_none() {
318303
return None;
@@ -464,7 +449,7 @@ mod impl_ {
464449
.collect()
465450
}
466451

467-
pub fn find_msvc_15plus(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
452+
pub(super) fn find_msvc_15plus(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
468453
let iter = vs15plus_instances(target)?;
469454
iter.into_iter()
470455
.filter_map(|instance| {
@@ -649,7 +634,7 @@ mod impl_ {
649634

650635
// For MSVC 14 we need to find the Universal CRT as well as either
651636
// the Windows 10 SDK or Windows 8.1 SDK.
652-
pub fn find_msvc_14(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
637+
pub(super) fn find_msvc_14(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
653638
let vcdir = get_vc_dir("14.0")?;
654639
let mut tool = get_tool(tool, &vcdir, target)?;
655640
add_sdks(&mut tool, target)?;
@@ -699,7 +684,7 @@ mod impl_ {
699684
}
700685

701686
// For MSVC 12 we need to find the Windows 8.1 SDK.
702-
pub fn find_msvc_12(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
687+
pub(super) fn find_msvc_12(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
703688
let vcdir = get_vc_dir("12.0")?;
704689
let mut tool = get_tool(tool, &vcdir, target)?;
705690
let sub = lib_subdir(target)?;
@@ -715,7 +700,7 @@ mod impl_ {
715700
}
716701

717702
// For MSVC 11 we need to find the Windows 8 SDK.
718-
pub fn find_msvc_11(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
703+
pub(super) fn find_msvc_11(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
719704
let vcdir = get_vc_dir("11.0")?;
720705
let mut tool = get_tool(tool, &vcdir, target)?;
721706
let sub = lib_subdir(target)?;
@@ -969,7 +954,7 @@ mod impl_ {
969954
max_key
970955
}
971956

972-
pub fn has_msbuild_version(version: &str) -> bool {
957+
pub(super) fn has_msbuild_version(version: &str) -> bool {
973958
match version {
974959
"17.0" => {
975960
find_msbuild_vs17(TargetArch("x86_64")).is_some()
@@ -996,7 +981,7 @@ mod impl_ {
996981
}
997982
}
998983

999-
pub fn find_devenv(target: TargetArch<'_>) -> Option<Tool> {
984+
pub(super) fn find_devenv(target: TargetArch<'_>) -> Option<Tool> {
1000985
find_devenv_vs15(target)
1001986
}
1002987

@@ -1005,7 +990,7 @@ mod impl_ {
1005990
}
1006991

1007992
// see http://stackoverflow.com/questions/328017/path-to-msbuild
1008-
pub fn find_msbuild(target: TargetArch<'_>) -> Option<Tool> {
993+
pub(super) fn find_msbuild(target: TargetArch<'_>) -> Option<Tool> {
1009994
// VS 15 (2017) changed how to locate msbuild
1010995
if let Some(r) = find_msbuild_vs17(target) {
1011996
Some(r)
@@ -1041,3 +1026,75 @@ mod impl_ {
10411026
})
10421027
}
10431028
}
1029+
1030+
/// Non-Windows Implementation.
1031+
#[cfg(not(windows))]
1032+
mod impl_ {
1033+
use std::{env, ffi::OsString};
1034+
1035+
use super::{TargetArch, MSVC_FAMILY};
1036+
use crate::Tool;
1037+
1038+
/// Finding msbuild.exe tool under unix system is not currently supported.
1039+
/// Maybe can check it using an environment variable looks like `MSBUILD_BIN`.
1040+
pub(super) fn find_msbuild(_target: TargetArch<'_>) -> Option<Tool> {
1041+
None
1042+
}
1043+
1044+
// Finding devenv.exe tool under unix system is not currently supported.
1045+
// Maybe can check it using an environment variable looks like `DEVENV_BIN`.
1046+
pub(super) fn find_devenv(_target: TargetArch<'_>) -> Option<Tool> {
1047+
None
1048+
}
1049+
1050+
/// Attempt to find the tool using environment variables set by vcvars.
1051+
pub(super) fn find_msvc_environment(tool: &str, _target: TargetArch<'_>) -> Option<Tool> {
1052+
// Early return if the environment doesn't contain a VC install.
1053+
let vc_install_dir = env::var_os("VCINSTALLDIR")?;
1054+
let vs_install_dir = env::var_os("VSINSTALLDIR")?;
1055+
1056+
let get_tool = |install_dir: OsString| {
1057+
env::split_paths(&install_dir)
1058+
.map(|p| p.join(tool))
1059+
.find(|p| p.exists())
1060+
.map(|path| Tool::with_family(path.into(), MSVC_FAMILY))
1061+
};
1062+
1063+
// Take the path of tool for the vc install directory.
1064+
get_tool(vc_install_dir)
1065+
// Take the path of tool for the vs install directory.
1066+
.or_else(|| get_tool(vs_install_dir))
1067+
// Take the path of tool for the current path environment.
1068+
.or_else(|| env::var_os("PATH").and_then(|path| get_tool(path)))
1069+
}
1070+
1071+
pub(super) fn find_msvc_15plus(_tool: &str, _target: TargetArch<'_>) -> Option<Tool> {
1072+
None
1073+
}
1074+
1075+
// For MSVC 14 we need to find the Universal CRT as well as either
1076+
// the Windows 10 SDK or Windows 8.1 SDK.
1077+
pub(super) fn find_msvc_14(_tool: &str, _target: TargetArch<'_>) -> Option<Tool> {
1078+
None
1079+
}
1080+
1081+
// For MSVC 12 we need to find the Windows 8.1 SDK.
1082+
pub(super) fn find_msvc_12(_tool: &str, _target: TargetArch<'_>) -> Option<Tool> {
1083+
None
1084+
}
1085+
1086+
// For MSVC 11 we need to find the Windows 8 SDK.
1087+
pub(super) fn find_msvc_11(_tool: &str, _target: TargetArch<'_>) -> Option<Tool> {
1088+
None
1089+
}
1090+
1091+
pub(super) fn has_msbuild_version(version: &str) -> bool {
1092+
match version {
1093+
"17.0" => false,
1094+
"16.0" => false,
1095+
"15.0" => false,
1096+
"12.0" | "14.0" => false,
1097+
_ => false,
1098+
}
1099+
}
1100+
}

0 commit comments

Comments
 (0)