Skip to content

Commit 3162fbe

Browse files
author
cavivie
committed
Support finding windows tools on non-Windows host
1 parent 8cf5455 commit 3162fbe

File tree

2 files changed

+110
-51
lines changed

2 files changed

+110
-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: 110 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,39 @@
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
15+
#![allow(clippy::upper_case_acronyms)]
1416
#![allow(clippy::upper_case_acronyms)]
1517

1618
use std::process::Command;
1719

1820
use crate::Tool;
19-
#[cfg(windows)]
2021
use crate::ToolFamily;
2122

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

25-
/// Attempts to find a tool within an MSVC installation using the Windows
26-
/// registry as a point to search from.
25+
#[derive(Copy, Clone)]
26+
struct TargetArch<'a>(pub &'a str);
27+
28+
impl PartialEq<&str> for TargetArch<'_> {
29+
fn eq(&self, other: &&str) -> bool {
30+
self.0 == *other
31+
}
32+
}
33+
34+
impl<'a> From<TargetArch<'a>> for &'a str {
35+
fn from(target: TargetArch<'a>) -> Self {
36+
target.0
37+
}
38+
}
39+
40+
/// Attempts to find a tool within an MSVC installation:
41+
/// 1. On Windows host, using the Windows registry as a point to search from;
42+
/// 2. On non-Windows host, using related environment variables to search from.
43+
///
2744
///
2845
/// The `target` argument is the target that the tool should work for (e.g.
2946
/// 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<Command> {
4158
/// Similar to the `find` function above, this function will attempt the same
4259
/// operation (finding a MSVC tool in a local install) but instead returns a
4360
/// `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)]
5161
pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
5262
// This logic is all tailored for MSVC, if we're not that then bail out
5363
// early.
@@ -56,15 +66,16 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
5666
}
5767

5868
// Split the target to get the arch.
59-
let target = impl_::TargetArch(target.split_once('-')?.0);
69+
let target = TargetArch(target.split_once('-')?.0);
6070

6171
// 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.
72+
// cl.exe and lib.exe.
6473
if tool.contains("msbuild") {
6574
return impl_::find_msbuild(target);
6675
}
6776

77+
// Looks like devenv isn't located in the same location as other tools like
78+
// cl.exe and lib.exe.
6879
if tool.contains("devenv") {
6980
return impl_::find_devenv(target);
7081
}
@@ -103,17 +114,8 @@ pub enum VsVers {
103114
///
104115
/// This is used by the cmake crate to figure out the correct
105116
/// generator.
106-
#[cfg(not(windows))]
107117
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") {
118+
match std::env::var("VisualStudioVersion") {
117119
Ok(version) => match &version[..] {
118120
"17.0" => Ok(VsVers::Vs17),
119121
"16.0" => Ok(VsVers::Vs16),
@@ -157,6 +159,7 @@ pub fn find_vs_version() -> Result<VsVers, String> {
157159
}
158160
}
159161

162+
/// Windows Implementation.
160163
#[cfg(windows)]
161164
mod impl_ {
162165
use crate::com;
@@ -174,24 +177,9 @@ mod impl_ {
174177
use std::process::Command;
175178
use std::str::FromStr;
176179

177-
use super::MSVC_FAMILY;
180+
use super::{TargetArch, MSVC_FAMILY};
178181
use crate::Tool;
179182

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-
195183
struct MsvcTool {
196184
tool: PathBuf,
197185
libs: Vec<PathBuf>,
@@ -242,7 +230,7 @@ mod impl_ {
242230
}
243231

244232
/// Attempt to find the tool using environment variables set by vcvars.
245-
pub fn find_msvc_environment(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
233+
pub(super) fn find_msvc_environment(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
246234
// Early return if the environment doesn't contain a VC install.
247235
if env::var_os("VCINSTALLDIR").is_none() {
248236
return None;
@@ -394,7 +382,7 @@ mod impl_ {
394382
.collect()
395383
}
396384

397-
pub fn find_msvc_15plus(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
385+
pub(super) fn find_msvc_15plus(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
398386
let iter = vs15plus_instances(target)?;
399387
iter.into_iter()
400388
.filter_map(|instance| {
@@ -565,7 +553,7 @@ mod impl_ {
565553

566554
// For MSVC 14 we need to find the Universal CRT as well as either
567555
// the Windows 10 SDK or Windows 8.1 SDK.
568-
pub fn find_msvc_14(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
556+
pub(super) fn find_msvc_14(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
569557
let vcdir = get_vc_dir("14.0")?;
570558
let mut tool = get_tool(tool, &vcdir, target)?;
571559
add_sdks(&mut tool, target)?;
@@ -615,7 +603,7 @@ mod impl_ {
615603
}
616604

617605
// For MSVC 12 we need to find the Windows 8.1 SDK.
618-
pub fn find_msvc_12(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
606+
pub(super) fn find_msvc_12(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
619607
let vcdir = get_vc_dir("12.0")?;
620608
let mut tool = get_tool(tool, &vcdir, target)?;
621609
let sub = lib_subdir(target)?;
@@ -631,7 +619,7 @@ mod impl_ {
631619
}
632620

633621
// For MSVC 11 we need to find the Windows 8 SDK.
634-
pub fn find_msvc_11(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
622+
pub(super) fn find_msvc_11(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
635623
let vcdir = get_vc_dir("11.0")?;
636624
let mut tool = get_tool(tool, &vcdir, target)?;
637625
let sub = lib_subdir(target)?;
@@ -885,7 +873,7 @@ mod impl_ {
885873
max_key
886874
}
887875

888-
pub fn has_msbuild_version(version: &str) -> bool {
876+
pub(super) fn has_msbuild_version(version: &str) -> bool {
889877
match version {
890878
"17.0" => {
891879
find_msbuild_vs17(TargetArch("x86_64")).is_some()
@@ -912,16 +900,18 @@ mod impl_ {
912900
}
913901
}
914902

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

919908
fn find_devenv_vs15(target: TargetArch<'_>) -> Option<Tool> {
920909
find_tool_in_vs15_path(r"Common7\IDE\devenv.exe", target)
921910
}
922911

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

0 commit comments

Comments
 (0)