@@ -80,7 +80,7 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
8080 // environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that
8181 // the tool is actually usable.
8282
83- return impl_:: find_msvc_15 ( tool, target)
83+ return impl_:: find_msvc_15plus ( tool, target)
8484 . or_else ( || impl_:: find_msvc_14 ( tool, target) )
8585 . or_else ( || impl_:: find_msvc_12 ( tool, target) )
8686 . or_else ( || impl_:: find_msvc_11 ( tool, target) ) ;
@@ -173,6 +173,7 @@ mod impl_ {
173173 use std:: iter;
174174 use std:: mem;
175175 use std:: path:: { Path , PathBuf } ;
176+ use std:: str:: FromStr ;
176177
177178 use crate :: Tool ;
178179
@@ -210,7 +211,7 @@ mod impl_ {
210211
211212 #[ allow( bare_trait_objects) ]
212213 fn vs16_instances ( ) -> Box < Iterator < Item = PathBuf > > {
213- let instances = if let Some ( instances) = vs15_instances ( ) {
214+ let instances = if let Some ( instances) = vs15plus_instances ( ) {
214215 instances
215216 } else {
216217 return Box :: new ( iter:: empty ( ) ) ;
@@ -253,24 +254,34 @@ mod impl_ {
253254 // Note that much of this logic can be found [online] wrt paths, COM, etc.
254255 //
255256 // [online]: https://blogs.msdn.microsoft.com/vcblog/2017/03/06/finding-the-visual-c-compiler-tools-in-visual-studio-2017/
256- fn vs15_instances ( ) -> Option < EnumSetupInstances > {
257+ //
258+ // Returns MSVC 15+ instances (15, 16 right now), the order should be consider undefined.
259+ fn vs15plus_instances ( ) -> Option < EnumSetupInstances > {
257260 com:: initialize ( ) . ok ( ) ?;
258261
259262 let config = SetupConfiguration :: new ( ) . ok ( ) ?;
260263 config. enum_all_instances ( ) . ok ( )
261264 }
262265
263- pub fn find_msvc_15 ( tool : & str , target : & str ) -> Option < Tool > {
264- let iter = vs15_instances ( ) ?;
265- for instance in iter {
266- let instance = instance. ok ( ) ?;
267- let tool = tool_from_vs15_instance ( tool, target, & instance) ;
268- if tool. is_some ( ) {
269- return tool;
270- }
271- }
266+ // Inspired from official microsoft/vswhere ParseVersionString
267+ // i.e. at most four u16 numbers separated by '.'
268+ fn parse_version ( version : & str ) -> Option < Vec < u16 > > {
269+ version
270+ . split ( '.' )
271+ . map ( |chunk| u16:: from_str ( chunk) . ok ( ) )
272+ . collect ( )
273+ }
272274
273- None
275+ pub fn find_msvc_15plus ( tool : & str , target : & str ) -> Option < Tool > {
276+ let iter = vs15plus_instances ( ) ?;
277+ iter. filter_map ( |instance| {
278+ let instance = instance. ok ( ) ?;
279+ let version = parse_version ( instance. installation_version ( ) . ok ( ) ?. to_str ( ) ?) ?;
280+ let tool = tool_from_vs15plus_instance ( tool, target, & instance) ?;
281+ Some ( ( version, tool) )
282+ } )
283+ . max_by ( |( a_version, _) , ( b_version, _) | a_version. cmp ( b_version) )
284+ . map ( |( _version, tool) | tool)
274285 }
275286
276287 // While the paths to Visual Studio 2017's devenv and MSBuild could
@@ -281,7 +292,7 @@ mod impl_ {
281292 //
282293 // [more reliable]: https://github.com/alexcrichton/cc-rs/pull/331
283294 fn find_tool_in_vs15_path ( tool : & str , target : & str ) -> Option < Tool > {
284- let mut path = match vs15_instances ( ) {
295+ let mut path = match vs15plus_instances ( ) {
285296 Some ( instances) => instances
286297 . filter_map ( |instance| {
287298 instance
@@ -312,8 +323,13 @@ mod impl_ {
312323 } )
313324 }
314325
315- fn tool_from_vs15_instance ( tool : & str , target : & str , instance : & SetupInstance ) -> Option < Tool > {
316- let ( bin_path, host_dylib_path, lib_path, include_path) = vs15_vc_paths ( target, instance) ?;
326+ fn tool_from_vs15plus_instance (
327+ tool : & str ,
328+ target : & str ,
329+ instance : & SetupInstance ,
330+ ) -> Option < Tool > {
331+ let ( bin_path, host_dylib_path, lib_path, include_path) =
332+ vs15plus_vc_paths ( target, instance) ?;
317333 let tool_path = bin_path. join ( tool) ;
318334 if !tool_path. exists ( ) {
319335 return None ;
@@ -334,7 +350,7 @@ mod impl_ {
334350 Some ( tool. into_tool ( ) )
335351 }
336352
337- fn vs15_vc_paths (
353+ fn vs15plus_vc_paths (
338354 target : & str ,
339355 instance : & SetupInstance ,
340356 ) -> Option < ( PathBuf , PathBuf , PathBuf , PathBuf ) > {
0 commit comments