@@ -47,8 +47,6 @@ pub fn find_tool(_target: &str, _tool: &str) -> Option<Tool> {
47
47
/// Documented above.
48
48
#[ cfg( windows) ]
49
49
pub fn find_tool ( target : & str , tool : & str ) -> Option < Tool > {
50
- use std:: env;
51
-
52
50
// This logic is all tailored for MSVC, if we're not that then bail out
53
51
// early.
54
52
if !target. contains ( "msvc" ) {
@@ -66,26 +64,15 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
66
64
return impl_:: find_devenv ( target) ;
67
65
}
68
66
69
- // If VCINSTALLDIR is set, then someone's probably already run vcvars and we
70
- // should just find whatever that indicates.
71
- if env:: var_os ( "VCINSTALLDIR" ) . is_some ( ) {
72
- return env:: var_os ( "PATH" )
73
- . and_then ( |path| {
74
- env:: split_paths ( & path)
75
- . map ( |p| p. join ( tool) )
76
- . find ( |p| p. exists ( ) )
77
- } )
78
- . map ( |path| Tool :: with_family ( path. into ( ) , MSVC_FAMILY ) ) ;
79
- }
80
-
81
67
// Ok, if we're here, now comes the fun part of the probing. Default shells
82
68
// or shells like MSYS aren't really configured to execute `cl.exe` and the
83
69
// various compiler tools shipped as part of Visual Studio. Here we try to
84
70
// first find the relevant tool, then we also have to be sure to fill in
85
71
// environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that
86
72
// the tool is actually usable.
87
73
88
- return impl_:: find_msvc_15plus ( tool, target)
74
+ return impl_:: find_msvc_environment ( tool, target)
75
+ . or_else ( || impl_:: find_msvc_15plus ( tool, target) )
89
76
. or_else ( || impl_:: find_msvc_14 ( tool, target) )
90
77
. or_else ( || impl_:: find_msvc_12 ( tool, target) )
91
78
. or_else ( || impl_:: find_msvc_11 ( tool, target) ) ;
@@ -218,6 +205,48 @@ mod impl_ {
218
205
}
219
206
}
220
207
208
+ /// Checks to see if the `VSCMD_ARG_TGT_ARCH` environment variable matches the
209
+ /// given target's arch. Returns `None` if the variable does not exist.
210
+ #[ cfg( windows) ]
211
+ fn is_vscmd_target ( target : & str ) -> Option < bool > {
212
+ let vscmd_arch = env:: var ( "VSCMD_ARG_TGT_ARCH" ) . ok ( ) ?;
213
+ // Convert the Rust target arch to its VS arch equivalent.
214
+ let arch = match target. split ( "-" ) . next ( ) {
215
+ Some ( "x86_64" ) => "x64" ,
216
+ Some ( "aarch64" ) => "arm64" ,
217
+ Some ( "i686" ) | Some ( "i586" ) => "x86" ,
218
+ Some ( "thumbv7a" ) => "arm" ,
219
+ // An unrecognized arch.
220
+ _ => return Some ( false ) ,
221
+ } ;
222
+ Some ( vscmd_arch == arch)
223
+ }
224
+
225
+ /// Attempt to find the tool using environment variables set by vcvars.
226
+ pub fn find_msvc_environment ( target : & str , tool : & str ) -> Option < Tool > {
227
+ // Early return if the environment doesn't contain a VC install.
228
+ if env:: var_os ( "VCINSTALLDIR" ) . is_none ( ) {
229
+ return None ;
230
+ }
231
+ let vs_install_dir = env:: var_os ( "VSINSTALLDIR" ) ?. into ( ) ;
232
+
233
+ // If the vscmd target differs from the requested target then
234
+ // attempt to get the tool using the VS install directory.
235
+ if is_vscmd_target ( target) == Some ( false ) {
236
+ // We will only get here with versions 15+.
237
+ tool_from_vs15plus_instance ( tool, target, & vs_install_dir)
238
+ } else {
239
+ // Fallback to simply using the current environment.
240
+ env:: var_os ( "PATH" )
241
+ . and_then ( |path| {
242
+ env:: split_paths ( & path)
243
+ . map ( |p| p. join ( tool) )
244
+ . find ( |p| p. exists ( ) )
245
+ } )
246
+ . map ( |path| Tool :: with_family ( path. into ( ) , MSVC_FAMILY ) )
247
+ }
248
+ }
249
+
221
250
#[ allow( bare_trait_objects) ]
222
251
fn vs16_instances ( target : & str ) -> Box < Iterator < Item = PathBuf > > {
223
252
let instances = if let Some ( instances) = vs15plus_instances ( target) {
0 commit comments