]> git.proxmox.com Git - cargo.git/blob - vendor/cc-1.0.0/src/windows_registry.rs
New upstream version 0.23.0
[cargo.git] / vendor / cc-1.0.0 / src / windows_registry.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! A helper module to probe the Windows Registry when looking for
12 //! windows-specific tools.
13
14 use std::process::Command;
15
16 use Tool;
17
18 #[cfg(windows)]
19 macro_rules! otry {
20 ($expr:expr) => (match $expr {
21 Some(val) => val,
22 None => return None,
23 })
24 }
25
26 /// Attempts to find a tool within an MSVC installation using the Windows
27 /// registry as a point to search from.
28 ///
29 /// The `target` argument is the target that the tool should work for (e.g.
30 /// compile or link for) and the `tool` argument is the tool to find (e.g.
31 /// `cl.exe` or `link.exe`).
32 ///
33 /// This function will return `None` if the tool could not be found, or it will
34 /// return `Some(cmd)` which represents a command that's ready to execute the
35 /// tool with the appropriate environment variables set.
36 ///
37 /// Note that this function always returns `None` for non-MSVC targets.
38 pub fn find(target: &str, tool: &str) -> Option<Command> {
39 find_tool(target, tool).map(|c| c.to_command())
40 }
41
42 /// Similar to the `find` function above, this function will attempt the same
43 /// operation (finding a MSVC tool in a local install) but instead returns a
44 /// `Tool` which may be introspected.
45 #[cfg(not(windows))]
46 pub fn find_tool(_target: &str, _tool: &str) -> Option<Tool> {
47 None
48 }
49
50 /// Documented above.
51 #[cfg(windows)]
52 pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
53 use std::env;
54
55 // This logic is all tailored for MSVC, if we're not that then bail out
56 // early.
57 if !target.contains("msvc") {
58 return None;
59 }
60
61 // 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.
64 if tool.contains("msbuild") {
65 return impl_::find_msbuild(target);
66 }
67
68 // If VCINSTALLDIR is set, then someone's probably already run vcvars and we
69 // should just find whatever that indicates.
70 if env::var_os("VCINSTALLDIR").is_some() {
71 return env::var_os("PATH")
72 .and_then(|path| env::split_paths(&path).map(|p| p.join(tool)).find(|p| p.exists()))
73 .map(|path| Tool::new(path.into()));
74 }
75
76 // Ok, if we're here, now comes the fun part of the probing. Default shells
77 // or shells like MSYS aren't really configured to execute `cl.exe` and the
78 // various compiler tools shipped as part of Visual Studio. Here we try to
79 // first find the relevant tool, then we also have to be sure to fill in
80 // environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that
81 // the tool is actually usable.
82
83 return impl_::find_msvc_15(tool, target)
84 .or_else(|| impl_::find_msvc_14(tool, target))
85 .or_else(|| impl_::find_msvc_12(tool, target))
86 .or_else(|| impl_::find_msvc_11(tool, target));
87 }
88
89 /// A version of Visual Studio
90 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
91 pub enum VsVers {
92 /// Visual Studio 12 (2013)
93 Vs12,
94 /// Visual Studio 14 (2015)
95 Vs14,
96 /// Visual Studio 15 (2017)
97 Vs15,
98
99 /// Hidden variant that should not be matched on. Callers that want to
100 /// handle an enumeration of `VsVers` instances should always have a default
101 /// case meaning that it's a VS version they don't understand.
102 #[doc(hidden)]
103 #[allow(bad_style)]
104 __Nonexhaustive_do_not_match_this_or_your_code_will_break,
105 }
106
107 /// Find the most recent installed version of Visual Studio
108 ///
109 /// This is used by the cmake crate to figure out the correct
110 /// generator.
111 #[cfg(not(windows))]
112 pub fn find_vs_version() -> Result<VsVers, String> {
113 Err(format!("not windows"))
114 }
115
116 /// Documented above
117 #[cfg(windows)]
118 pub fn find_vs_version() -> Result<VsVers, String> {
119 use std::env;
120
121 match env::var("VisualStudioVersion") {
122 Ok(version) => {
123 match &version[..] {
124 "15.0" => Ok(VsVers::Vs15),
125 "14.0" => Ok(VsVers::Vs14),
126 "12.0" => Ok(VsVers::Vs12),
127 vers => Err(format!("\n\n\
128 unsupported or unknown VisualStudio version: {}\n\
129 if another version is installed consider running \
130 the appropriate vcvars script before building this \
131 crate\n\
132 ", vers)),
133 }
134 }
135 _ => {
136 // Check for the presense of a specific registry key
137 // that indicates visual studio is installed.
138 if impl_::has_msbuild_version("15.0") {
139 Ok(VsVers::Vs15)
140 } else if impl_::has_msbuild_version("14.0") {
141 Ok(VsVers::Vs14)
142 } else if impl_::has_msbuild_version("12.0") {
143 Ok(VsVers::Vs12)
144 } else {
145 Err(format!("\n\n\
146 couldn't determine visual studio generator\n\
147 if VisualStudio is installed, however, consider \
148 running the appropriate vcvars script before building \
149 this crate\n\
150 "))
151 }
152 }
153 }
154 }
155
156 #[cfg(windows)]
157 mod impl_ {
158 use std::env;
159 use std::ffi::OsString;
160 use std::mem;
161 use std::path::{Path, PathBuf};
162 use std::fs::File;
163 use std::io::Read;
164 use registry::{RegistryKey, LOCAL_MACHINE};
165 use com;
166 use setup_config::{SetupConfiguration, SetupInstance};
167
168 use Tool;
169
170 struct MsvcTool {
171 tool: PathBuf,
172 libs: Vec<PathBuf>,
173 path: Vec<PathBuf>,
174 include: Vec<PathBuf>,
175 }
176
177 impl MsvcTool {
178 fn new(tool: PathBuf) -> MsvcTool {
179 MsvcTool {
180 tool: tool,
181 libs: Vec::new(),
182 path: Vec::new(),
183 include: Vec::new(),
184 }
185 }
186
187 fn into_tool(self) -> Tool {
188 let MsvcTool { tool, libs, path, include } = self;
189 let mut tool = Tool::new(tool.into());
190 add_env(&mut tool, "LIB", libs);
191 add_env(&mut tool, "PATH", path);
192 add_env(&mut tool, "INCLUDE", include);
193 tool
194 }
195 }
196
197 // In MSVC 15 (2017) MS once again changed the scheme for locating
198 // the tooling. Now we must go through some COM interfaces, which
199 // is super fun for Rust.
200 //
201 // Note that much of this logic can be found [online] wrt paths, COM, etc.
202 //
203 // [online]: https://blogs.msdn.microsoft.com/vcblog/2017/03/06/finding-the-visual-c-compiler-tools-in-visual-studio-2017/
204 pub fn find_msvc_15(tool: &str, target: &str) -> Option<Tool> {
205 otry!(com::initialize().ok());
206
207 let config = otry!(SetupConfiguration::new().ok());
208 let iter = otry!(config.enum_all_instances().ok());
209 for instance in iter {
210 let instance = otry!(instance.ok());
211 let tool = tool_from_vs15_instance(tool, target, &instance);
212 if tool.is_some() {
213 return tool;
214 }
215 }
216
217 None
218 }
219
220 fn tool_from_vs15_instance(tool: &str, target: &str,
221 instance: &SetupInstance) -> Option<Tool> {
222 let (bin_path, host_dylib_path, lib_path, include_path) = otry!(vs15_vc_paths(target, instance));
223 let tool_path = bin_path.join(tool);
224 if !tool_path.exists() { return None };
225
226 let mut tool = MsvcTool::new(tool_path);
227 tool.path.push(host_dylib_path);
228 tool.libs.push(lib_path);
229 tool.include.push(include_path);
230
231 if let Some((atl_lib_path, atl_include_path)) = atl_paths(target, &bin_path) {
232 tool.libs.push(atl_lib_path);
233 tool.include.push(atl_include_path);
234 }
235
236 otry!(add_sdks(&mut tool, target));
237
238 Some(tool.into_tool())
239 }
240
241 fn vs15_vc_paths(target: &str, instance: &SetupInstance) -> Option<(PathBuf, PathBuf, PathBuf, PathBuf)> {
242 let instance_path: PathBuf = otry!(instance.installation_path().ok()).into();
243 let version_path = instance_path.join(r"VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt");
244 let mut version_file = otry!(File::open(version_path).ok());
245 let mut version = String::new();
246 otry!(version_file.read_to_string(&mut version).ok());
247 let version = version.trim();
248 let host = match host_arch() {
249 X86 => "X86",
250 X86_64 => "X64",
251 _ => return None,
252 };
253 let target = otry!(lib_subdir(target));
254 // The directory layout here is MSVC/bin/Host$host/$target/
255 let path = instance_path.join(r"VC\Tools\MSVC").join(version);
256 // This is the path to the toolchain for a particular target, running
257 // on a given host
258 let bin_path = path.join("bin").join(&format!("Host{}", host)).join(&target);
259 // But! we also need PATH to contain the target directory for the host
260 // architecture, because it contains dlls like mspdb140.dll compiled for
261 // the host architecture.
262 let host_dylib_path = path.join("bin").join(&format!("Host{}", host)).join(&host.to_lowercase());
263 let lib_path = path.join("lib").join(&target);
264 let include_path = path.join("include");
265 Some((bin_path, host_dylib_path, lib_path, include_path))
266 }
267
268 fn atl_paths(target: &str, path: &Path) -> Option<(PathBuf, PathBuf)> {
269 let atl_path = path.join("atlfmc");
270 let sub = otry!(lib_subdir(target));
271 if atl_path.exists() {
272 Some((atl_path.join("lib").join(sub), atl_path.join("include")))
273 } else {
274 None
275 }
276 }
277
278 // For MSVC 14 we need to find the Universal CRT as well as either
279 // the Windows 10 SDK or Windows 8.1 SDK.
280 pub fn find_msvc_14(tool: &str, target: &str) -> Option<Tool> {
281 let vcdir = otry!(get_vc_dir("14.0"));
282 let mut tool = otry!(get_tool(tool, &vcdir, target));
283 otry!(add_sdks(&mut tool, target));
284 Some(tool.into_tool())
285 }
286
287 fn add_sdks(tool: &mut MsvcTool, target: &str) -> Option<()> {
288 let sub = otry!(lib_subdir(target));
289 let (ucrt, ucrt_version) = otry!(get_ucrt_dir());
290
291 tool.path.push(ucrt.join("bin").join(&ucrt_version).join(sub));
292
293 let ucrt_include = ucrt.join("include").join(&ucrt_version);
294 tool.include.push(ucrt_include.join("ucrt"));
295
296 let ucrt_lib = ucrt.join("lib").join(&ucrt_version);
297 tool.libs.push(ucrt_lib.join("ucrt").join(sub));
298
299 if let Some((sdk, version)) = get_sdk10_dir() {
300 tool.path.push(sdk.join("bin").join(sub));
301 let sdk_lib = sdk.join("lib").join(&version);
302 tool.libs.push(sdk_lib.join("um").join(sub));
303 let sdk_include = sdk.join("include").join(&version);
304 tool.include.push(sdk_include.join("um"));
305 tool.include.push(sdk_include.join("winrt"));
306 tool.include.push(sdk_include.join("shared"));
307 } else if let Some(sdk) = get_sdk81_dir() {
308 tool.path.push(sdk.join("bin").join(sub));
309 let sdk_lib = sdk.join("lib").join("winv6.3");
310 tool.libs.push(sdk_lib.join("um").join(sub));
311 let sdk_include = sdk.join("include");
312 tool.include.push(sdk_include.join("um"));
313 tool.include.push(sdk_include.join("winrt"));
314 tool.include.push(sdk_include.join("shared"));
315 }
316
317 Some(())
318 }
319
320 // For MSVC 12 we need to find the Windows 8.1 SDK.
321 pub fn find_msvc_12(tool: &str, target: &str) -> Option<Tool> {
322 let vcdir = otry!(get_vc_dir("12.0"));
323 let mut tool = otry!(get_tool(tool, &vcdir, target));
324 let sub = otry!(lib_subdir(target));
325 let sdk81 = otry!(get_sdk81_dir());
326 tool.path.push(sdk81.join("bin").join(sub));
327 let sdk_lib = sdk81.join("lib").join("winv6.3");
328 tool.libs.push(sdk_lib.join("um").join(sub));
329 let sdk_include = sdk81.join("include");
330 tool.include.push(sdk_include.join("shared"));
331 tool.include.push(sdk_include.join("um"));
332 tool.include.push(sdk_include.join("winrt"));
333 Some(tool.into_tool())
334 }
335
336 // For MSVC 11 we need to find the Windows 8 SDK.
337 pub fn find_msvc_11(tool: &str, target: &str) -> Option<Tool> {
338 let vcdir = otry!(get_vc_dir("11.0"));
339 let mut tool = otry!(get_tool(tool, &vcdir, target));
340 let sub = otry!(lib_subdir(target));
341 let sdk8 = otry!(get_sdk8_dir());
342 tool.path.push(sdk8.join("bin").join(sub));
343 let sdk_lib = sdk8.join("lib").join("win8");
344 tool.libs.push(sdk_lib.join("um").join(sub));
345 let sdk_include = sdk8.join("include");
346 tool.include.push(sdk_include.join("shared"));
347 tool.include.push(sdk_include.join("um"));
348 tool.include.push(sdk_include.join("winrt"));
349 Some(tool.into_tool())
350 }
351
352 fn add_env(tool: &mut Tool, env: &str, paths: Vec<PathBuf>) {
353 let prev = env::var_os(env).unwrap_or(OsString::new());
354 let prev = env::split_paths(&prev);
355 let new = paths.into_iter().chain(prev);
356 tool.env.push((env.to_string().into(), env::join_paths(new).unwrap()));
357 }
358
359 // Given a possible MSVC installation directory, we look for the linker and
360 // then add the MSVC library path.
361 fn get_tool(tool: &str, path: &Path, target: &str) -> Option<MsvcTool> {
362 bin_subdir(target)
363 .into_iter()
364 .map(|(sub, host)| (path.join("bin").join(sub).join(tool), path.join("bin").join(host)))
365 .filter(|&(ref path, _)| path.is_file())
366 .map(|(path, host)| {
367 let mut tool = MsvcTool::new(path);
368 tool.path.push(host);
369 tool
370 })
371 .filter_map(|mut tool| {
372 let sub = otry!(vc_lib_subdir(target));
373 tool.libs.push(path.join("lib").join(sub));
374 tool.include.push(path.join("include"));
375 let atlmfc_path = path.join("atlmfc");
376 if atlmfc_path.exists() {
377 tool.libs.push(atlmfc_path.join("lib").join(sub));
378 tool.include.push(atlmfc_path.join("include"));
379 }
380 Some(tool)
381 })
382 .next()
383 }
384
385 // To find MSVC we look in a specific registry key for the version we are
386 // trying to find.
387 fn get_vc_dir(ver: &str) -> Option<PathBuf> {
388 let key = r"SOFTWARE\Microsoft\VisualStudio\SxS\VC7";
389 let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok());
390 let path = otry!(key.query_str(ver).ok());
391 Some(path.into())
392 }
393
394 // To find the Universal CRT we look in a specific registry key for where
395 // all the Universal CRTs are located and then sort them asciibetically to
396 // find the newest version. While this sort of sorting isn't ideal, it is
397 // what vcvars does so that's good enough for us.
398 //
399 // Returns a pair of (root, version) for the ucrt dir if found
400 fn get_ucrt_dir() -> Option<(PathBuf, String)> {
401 let key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots";
402 let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok());
403 let root = otry!(key.query_str("KitsRoot10").ok());
404 let readdir = otry!(Path::new(&root).join("lib").read_dir().ok());
405 let max_libdir = otry!(readdir.filter_map(|dir| dir.ok())
406 .map(|dir| dir.path())
407 .filter(|dir| {
408 dir.components()
409 .last()
410 .and_then(|c| c.as_os_str().to_str())
411 .map(|c| c.starts_with("10.") && dir.join("ucrt").is_dir())
412 .unwrap_or(false)
413 })
414 .max());
415 let version = max_libdir.components().last().unwrap();
416 let version = version.as_os_str().to_str().unwrap().to_string();
417 Some((root.into(), version))
418 }
419
420 // Vcvars finds the correct version of the Windows 10 SDK by looking
421 // for the include `um\Windows.h` because sometimes a given version will
422 // only have UCRT bits without the rest of the SDK. Since we only care about
423 // libraries and not includes, we instead look for `um\x64\kernel32.lib`.
424 // Since the 32-bit and 64-bit libraries are always installed together we
425 // only need to bother checking x64, making this code a tiny bit simpler.
426 // Like we do for the Universal CRT, we sort the possibilities
427 // asciibetically to find the newest one as that is what vcvars does.
428 fn get_sdk10_dir() -> Option<(PathBuf, String)> {
429 let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0";
430 let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok());
431 let root = otry!(key.query_str("InstallationFolder").ok());
432 let readdir = otry!(Path::new(&root).join("lib").read_dir().ok());
433 let mut dirs = readdir.filter_map(|dir| dir.ok())
434 .map(|dir| dir.path())
435 .collect::<Vec<_>>();
436 dirs.sort();
437 let dir = otry!(dirs.into_iter()
438 .rev()
439 .filter(|dir| dir.join("um").join("x64").join("kernel32.lib").is_file())
440 .next());
441 let version = dir.components().last().unwrap();
442 let version = version.as_os_str().to_str().unwrap().to_string();
443 Some((root.into(), version))
444 }
445
446 // Interestingly there are several subdirectories, `win7` `win8` and
447 // `winv6.3`. Vcvars seems to only care about `winv6.3` though, so the same
448 // applies to us. Note that if we were targetting kernel mode drivers
449 // instead of user mode applications, we would care.
450 fn get_sdk81_dir() -> Option<PathBuf> {
451 let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1";
452 let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok());
453 let root = otry!(key.query_str("InstallationFolder").ok());
454 Some(root.into())
455 }
456
457 fn get_sdk8_dir() -> Option<PathBuf> {
458 let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0";
459 let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok());
460 let root = otry!(key.query_str("InstallationFolder").ok());
461 Some(root.into())
462 }
463
464 const PROCESSOR_ARCHITECTURE_INTEL: u16 = 0;
465 const PROCESSOR_ARCHITECTURE_AMD64: u16 = 9;
466 const X86: u16 = PROCESSOR_ARCHITECTURE_INTEL;
467 const X86_64: u16 = PROCESSOR_ARCHITECTURE_AMD64;
468
469 // When choosing the tool to use, we have to choose the one which matches
470 // the target architecture. Otherwise we end up in situations where someone
471 // on 32-bit Windows is trying to cross compile to 64-bit and it tries to
472 // invoke the native 64-bit compiler which won't work.
473 //
474 // For the return value of this function, the first member of the tuple is
475 // the folder of the tool we will be invoking, while the second member is
476 // the folder of the host toolchain for that tool which is essential when
477 // using a cross linker. We return a Vec since on x64 there are often two
478 // linkers that can target the architecture we desire. The 64-bit host
479 // linker is preferred, and hence first, due to 64-bit allowing it more
480 // address space to work with and potentially being faster.
481 fn bin_subdir(target: &str) -> Vec<(&'static str, &'static str)> {
482 let arch = target.split('-').next().unwrap();
483 match (arch, host_arch()) {
484 ("i586", X86) | ("i686", X86) => vec![("", "")],
485 ("i586", X86_64) | ("i686", X86_64) => vec![("amd64_x86", "amd64"), ("", "")],
486 ("x86_64", X86) => vec![("x86_amd64", "")],
487 ("x86_64", X86_64) => vec![("amd64", "amd64"), ("x86_amd64", "")],
488 ("arm", X86) => vec![("x86_arm", "")],
489 ("arm", X86_64) => vec![("amd64_arm", "amd64"), ("x86_arm", "")],
490 _ => vec![],
491 }
492 }
493
494 fn lib_subdir(target: &str) -> Option<&'static str> {
495 let arch = target.split('-').next().unwrap();
496 match arch {
497 "i586" | "i686" => Some("x86"),
498 "x86_64" => Some("x64"),
499 "arm" => Some("arm"),
500 _ => None,
501 }
502 }
503
504 // MSVC's x86 libraries are not in a subfolder
505 fn vc_lib_subdir(target: &str) -> Option<&'static str> {
506 let arch = target.split('-').next().unwrap();
507 match arch {
508 "i586" | "i686" => Some(""),
509 "x86_64" => Some("amd64"),
510 "arm" => Some("arm"),
511 _ => None,
512 }
513 }
514
515 #[allow(bad_style)]
516 fn host_arch() -> u16 {
517 type DWORD = u32;
518 type WORD = u16;
519 type LPVOID = *mut u8;
520 type DWORD_PTR = usize;
521
522 #[repr(C)]
523 struct SYSTEM_INFO {
524 wProcessorArchitecture: WORD,
525 _wReserved: WORD,
526 _dwPageSize: DWORD,
527 _lpMinimumApplicationAddress: LPVOID,
528 _lpMaximumApplicationAddress: LPVOID,
529 _dwActiveProcessorMask: DWORD_PTR,
530 _dwNumberOfProcessors: DWORD,
531 _dwProcessorType: DWORD,
532 _dwAllocationGranularity: DWORD,
533 _wProcessorLevel: WORD,
534 _wProcessorRevision: WORD,
535 }
536
537 extern "system" {
538 fn GetNativeSystemInfo(lpSystemInfo: *mut SYSTEM_INFO);
539 }
540
541 unsafe {
542 let mut info = mem::zeroed();
543 GetNativeSystemInfo(&mut info);
544 info.wProcessorArchitecture
545 }
546 }
547
548 // Given a registry key, look at all the sub keys and find the one which has
549 // the maximal numeric value.
550 //
551 // Returns the name of the maximal key as well as the opened maximal key.
552 fn max_version(key: &RegistryKey) -> Option<(OsString, RegistryKey)> {
553 let mut max_vers = 0;
554 let mut max_key = None;
555 for subkey in key.iter().filter_map(|k| k.ok()) {
556 let val = subkey.to_str()
557 .and_then(|s| s.trim_left_matches("v").replace(".", "").parse().ok());
558 let val = match val {
559 Some(s) => s,
560 None => continue,
561 };
562 if val > max_vers {
563 if let Ok(k) = key.open(&subkey) {
564 max_vers = val;
565 max_key = Some((subkey, k));
566 }
567 }
568 }
569 max_key
570 }
571
572 pub fn has_msbuild_version(version: &str) -> bool {
573 match version {
574 "15.0" => {
575 find_msbuild_vs15("x86_64-pc-windows-msvc").is_some() ||
576 find_msbuild_vs15("i686-pc-windows-msvc").is_some()
577 }
578 "12.0" | "14.0" => {
579 LOCAL_MACHINE.open(
580 &OsString::from(format!("SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\{}",
581 version))).is_ok()
582 }
583 _ => false
584 }
585 }
586
587 // see http://stackoverflow.com/questions/328017/path-to-msbuild
588 pub fn find_msbuild(target: &str) -> Option<Tool> {
589 // VS 15 (2017) changed how to locate msbuild
590 if let Some(r) = find_msbuild_vs15(target) {
591 return Some(r);
592 } else {
593 find_old_msbuild(target)
594 }
595 }
596
597 fn find_msbuild_vs15(target: &str) -> Option<Tool> {
598 // Seems like this could also go through SetupConfiguration,
599 // or that find_msvc_15 could just use this registry key
600 // instead of the COM interface.
601 let key = r"SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7";
602 LOCAL_MACHINE.open(key.as_ref())
603 .ok()
604 .and_then(|key| {
605 key.query_str("15.0").ok()
606 })
607 .map(|path| {
608 let path = PathBuf::from(path).join(r"MSBuild\15.0\Bin\MSBuild.exe");
609 let mut tool = Tool::new(path);
610 if target.contains("x86_64") {
611 tool.env.push(("Platform".into(), "X64".into()));
612 }
613 tool
614 })
615 }
616
617 fn find_old_msbuild(target: &str) -> Option<Tool> {
618 let key = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions";
619 LOCAL_MACHINE.open(key.as_ref())
620 .ok()
621 .and_then(|key| {
622 max_version(&key).and_then(|(_vers, key)| key.query_str("MSBuildToolsPath").ok())
623 })
624 .map(|path| {
625 let mut path = PathBuf::from(path);
626 path.push("MSBuild.exe");
627 let mut tool = Tool::new(path);
628 if target.contains("x86_64") {
629 tool.env.push(("Platform".into(), "X64".into()));
630 }
631 tool
632 })
633 }
634 }