Skip to content

Commit a2920da

Browse files
committed
fix find_tool and find_vs_version might returns incompatible values
On windows, I have both MSVC 15 and 16 and found out that find_vs_version returns MSVC 16 while find_tool returns MSVC 15 linker.
1 parent 383f2df commit a2920da

File tree

1 file changed

+33
-17
lines changed

1 file changed

+33
-17
lines changed

src/windows_registry.rs

+33-17
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)