Browse Source

Find devenv and MSBuild via SetupConfiguration rather than registry keys

After I recently uninstalled some older MSVC versions using Visual Studio
Uninstaller (https://github.com/Microsoft/VisualStudioUninstaller),
HKLM\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7\15.0 also was
deleted in the process, even though Visual Studio 2017 *itself* wasn't,
and still worked fine.

Steps to reproduce:
1. Install Visual Studio 2017 Community with the *Desktop development
   with C++* workload on a fresh Windows system. (I tested with version
   15.7.6.)
2. Confirm that the registry key points to the installation directory.
3. Run the Visual Studio Uninstaller on that same system.
4. The registry key is now gone, but Visual Studio 2017 IDE still works
   and can compile code.
5. The following Rust code then runs without panicking:

```rust
extern crate cc;

use cc::windows_registry::find_tool;

fn main() {
	// Change this if your test system is 32-bit
	let target = "x86_64-pc-windows-msvc";
	assert_eq!(find_tool(target, "devenv.exe").is_none(), true);
	assert_eq!(find_tool(target, "link.exe").is_some(), true);
	// msbuild.exe will fall back on find_old_msbuild(), which will
	// find a ersion under a different registry key.
}
```

Which means that `link.exe` can still be found just fine through
SetupConfiguration. This may be a bug in Visual Studio Uninstaller, but
it also matches what Microsoft says about the reliability of these
registry keys, and that SetupConfiguration should be preferred. (See
https://developercommunity.visualstudio.com/comments/215399/view.html).
wintest
nmlgc 6 years ago
parent
commit
123919c055
  1. 55
      src/windows_registry.rs

55
src/windows_registry.rs

@ -237,6 +237,30 @@ mod impl_ {
None None
} }
// It may seem that the paths to Visual Studio 2017's devenv and MSBuild
// could also be retrieved from the [registry], but SetupConfiguration's
// method seems to be [more reliable], and preferred according to Microsoft.
//
// [registry]: HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7
// [more reliable]: https://github.com/alexcrichton/cc-rs/pull/331
fn find_tool_in_vs15_path(tool: &str, target: &str) -> Option<Tool> {
otry!(vs15_instances())
.filter_map(|instance| {
instance
.ok()
.and_then(|instance| instance.installation_path().ok())
})
.map(|ip| PathBuf::from(ip).join(tool))
.map(|path| {
let mut tool = Tool::new(path);
if target.contains("x86_64") {
tool.env.push(("Platform".into(), "X64".into()));
}
tool
})
.next()
}
fn tool_from_vs15_instance(tool: &str, target: &str, instance: &SetupInstance) -> Option<Tool> { fn tool_from_vs15_instance(tool: &str, target: &str, instance: &SetupInstance) -> Option<Tool> {
let (bin_path, host_dylib_path, lib_path, include_path) = let (bin_path, host_dylib_path, lib_path, include_path) =
otry!(vs15_vc_paths(target, instance)); otry!(vs15_vc_paths(target, instance));
@ -635,19 +659,7 @@ mod impl_ {
} }
fn find_devenv_vs15(target: &str) -> Option<Tool> { fn find_devenv_vs15(target: &str) -> Option<Tool> {
let key = r"SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7"; find_tool_in_vs15_path(r"Common7\IDE\devenv.exe", target)
LOCAL_MACHINE
.open(key.as_ref())
.ok()
.and_then(|key| key.query_str("15.0").ok())
.map(|path| {
let path = PathBuf::from(path).join(r"Common7\IDE\devenv.exe");
let mut tool = Tool::new(path);
if target.contains("x86_64") {
tool.env.push(("Platform".into(), "X64".into()));
}
tool
})
} }
// see http://stackoverflow.com/questions/328017/path-to-msbuild // see http://stackoverflow.com/questions/328017/path-to-msbuild
@ -661,22 +673,7 @@ mod impl_ {
} }
fn find_msbuild_vs15(target: &str) -> Option<Tool> { fn find_msbuild_vs15(target: &str) -> Option<Tool> {
// Seems like this could also go through SetupConfiguration, find_tool_in_vs15_path(r"MSBuild\15.0\Bin\MSBuild.exe", target)
// or that find_msvc_15 could just use this registry key
// instead of the COM interface.
let key = r"SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7";
LOCAL_MACHINE
.open(key.as_ref())
.ok()
.and_then(|key| key.query_str("15.0").ok())
.map(|path| {
let path = PathBuf::from(path).join(r"MSBuild\15.0\Bin\MSBuild.exe");
let mut tool = Tool::new(path);
if target.contains("x86_64") {
tool.env.push(("Platform".into(), "X64".into()));
}
tool
})
} }
fn find_old_msbuild(target: &str) -> Option<Tool> { fn find_old_msbuild(target: &str) -> Option<Tool> {

Loading…
Cancel
Save