@@ -47,8 +47,6 @@ pub fn find_tool(_target: &str, _tool: &str) -> Option<Tool> {
4747/// Documented above.
4848#[ cfg( windows) ]
4949pub fn find_tool ( target : & str , tool : & str ) -> Option < Tool > {
50- use std:: env;
51-
5250 // This logic is all tailored for MSVC, if we're not that then bail out
5351 // early.
5452 if !target. contains ( "msvc" ) {
@@ -66,26 +64,15 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
6664 return impl_:: find_devenv ( target) ;
6765 }
6866
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-
8167 // Ok, if we're here, now comes the fun part of the probing. Default shells
8268 // or shells like MSYS aren't really configured to execute `cl.exe` and the
8369 // various compiler tools shipped as part of Visual Studio. Here we try to
8470 // first find the relevant tool, then we also have to be sure to fill in
8571 // environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that
8672 // the tool is actually usable.
8773
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) )
8976 . or_else ( || impl_:: find_msvc_14 ( tool, target) )
9077 . or_else ( || impl_:: find_msvc_12 ( tool, target) )
9178 . or_else ( || impl_:: find_msvc_11 ( tool, target) ) ;
@@ -218,6 +205,48 @@ mod impl_ {
218205 }
219206 }
220207
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+
221250 #[ allow( bare_trait_objects) ]
222251 fn vs16_instances ( target : & str ) -> Box < Iterator < Item = PathBuf > > {
223252 let instances = if let Some ( instances) = vs15plus_instances ( target) {
0 commit comments