Skip to content

Commit e981e65

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

File tree

2 files changed

+111
-51
lines changed

2 files changed

+111
-51
lines changed

src/lib.rs

-1
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

+111-50
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,40 @@
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.
14+
15+
#![allow(clippy::upper_case_acronyms)]
1316

1417
#![allow(clippy::upper_case_acronyms)]
1518

1619
use std::process::Command;
1720

1821
use crate::Tool;
19-
#[cfg(windows)]
2022
use crate::ToolFamily;
2123

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

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

5869
// Split the target to get the arch.
59-
let target = impl_::TargetArch(target.split_once('-')?.0);
70+
let target = TargetArch(target.split_once('-')?.0);
6071

6172
// 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.
73+
// cl.exe and lib.exe.
6474
if tool.contains("msbuild") {
6575
return impl_::find_msbuild(target);
6676
}
6777

78+
// Looks like devenv isn't located in the same location as other tools like
79+
// cl.exe and lib.exe.
6880
if tool.contains("devenv") {
6981
return impl_::find_devenv(target);
7082
}
@@ -103,17 +115,8 @@ pub enum VsVers {
103115
///
104116
/// This is used by the cmake crate to figure out the correct
105117
/// 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)]
113118
pub fn find_vs_version() -> Result<VsVers, String> {
114-
use std::env;
115-
116-
match env::var("VisualStudioVersion") {
119+
match std::env::var("VisualStudioVersion") {
117120
Ok(version) => match &version[..] {
118121
"17.0" => Ok(VsVers::Vs17),
119122
"16.0" => Ok(VsVers::Vs16),
@@ -157,6 +160,7 @@ pub fn find_vs_version() -> Result<VsVers, String> {
157160
}
158161
}
159162

163+
/// Windows Implementation.
160164
#[cfg(windows)]
161165
mod impl_ {
162166
use crate::com;
@@ -174,24 +178,9 @@ mod impl_ {
174178
use std::process::Command;
175179
use std::str::FromStr;
176180

177-
use super::MSVC_FAMILY;
181+
use super::{TargetArch, MSVC_FAMILY};
178182
use crate::Tool;
179183

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-
195184
struct MsvcTool {
196185
tool: PathBuf,
197186
libs: Vec<PathBuf>,
@@ -242,7 +231,7 @@ mod impl_ {
242231
}
243232

244233
/// Attempt to find the tool using environment variables set by vcvars.
245-
pub fn find_msvc_environment(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
234+
pub(super) fn find_msvc_environment(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
246235
// Early return if the environment doesn't contain a VC install.
247236
if env::var_os("VCINSTALLDIR").is_none() {
248237
return None;
@@ -394,7 +383,7 @@ mod impl_ {
394383
.collect()
395384
}
396385

397-
pub fn find_msvc_15plus(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
386+
pub(super) fn find_msvc_15plus(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
398387
let iter = vs15plus_instances(target)?;
399388
iter.into_iter()
400389
.filter_map(|instance| {
@@ -565,7 +554,7 @@ mod impl_ {
565554

566555
// For MSVC 14 we need to find the Universal CRT as well as either
567556
// the Windows 10 SDK or Windows 8.1 SDK.
568-
pub fn find_msvc_14(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
557+
pub(super) fn find_msvc_14(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
569558
let vcdir = get_vc_dir("14.0")?;
570559
let mut tool = get_tool(tool, &vcdir, target)?;
571560
add_sdks(&mut tool, target)?;
@@ -615,7 +604,7 @@ mod impl_ {
615604
}
616605

617606
// For MSVC 12 we need to find the Windows 8.1 SDK.
618-
pub fn find_msvc_12(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
607+
pub(super) fn find_msvc_12(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
619608
let vcdir = get_vc_dir("12.0")?;
620609
let mut tool = get_tool(tool, &vcdir, target)?;
621610
let sub = lib_subdir(target)?;
@@ -631,7 +620,7 @@ mod impl_ {
631620
}
632621

633622
// For MSVC 11 we need to find the Windows 8 SDK.
634-
pub fn find_msvc_11(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
623+
pub(super) fn find_msvc_11(tool: &str, target: TargetArch<'_>) -> Option<Tool> {
635624
let vcdir = get_vc_dir("11.0")?;
636625
let mut tool = get_tool(tool, &vcdir, target)?;
637626
let sub = lib_subdir(target)?;
@@ -885,7 +874,7 @@ mod impl_ {
885874
max_key
886875
}
887876

888-
pub fn has_msbuild_version(version: &str) -> bool {
877+
pub(super) fn has_msbuild_version(version: &str) -> bool {
889878
match version {
890879
"17.0" => {
891880
find_msbuild_vs17(TargetArch("x86_64")).is_some()
@@ -912,16 +901,18 @@ mod impl_ {
912901
}
913902
}
914903

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

919909
fn find_devenv_vs15(target: TargetArch<'_>) -> Option<Tool> {
920910
find_tool_in_vs15_path(r"Common7\IDE\devenv.exe", target)
921911
}
922912

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

0 commit comments

Comments
 (0)