Skip to content

Commit 742867f

Browse files
committed
Offer to auto install VS 2022
If there are no MSVC build tools already installed then default to auto installing Visual Studio 2022 Community Edition.
1 parent d080411 commit 742867f

File tree

2 files changed

+135
-8
lines changed

2 files changed

+135
-8
lines changed

src/cli/self_update.rs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,11 @@ static MSVC_MESSAGE: &str = r#"# Rust Visual C++ prerequisites
276276
Rust requires the Microsoft C++ build tools for Visual Studio 2013 or
277277
later, but they don't seem to be installed.
278278
279-
The easiest way to acquire the build tools is by installing Microsoft
279+
"#;
280+
281+
#[cfg(windows)]
282+
static MSVC_MANUAL_INSTALL_MESSAGE: &str = r#"
283+
You can acquire the build tools by installing Microsoft
280284
Visual C++ Build Tools 2019 which provides just the Visual C++ build
281285
tools:
282286
@@ -299,6 +303,15 @@ doing then it is fine to continue installation without the build
299303
tools, but otherwise, install the C++ build tools before proceeding.
300304
"#;
301305

306+
#[cfg(windows)]
307+
static MSVC_AUTO_INSTALL_MESSAGE: &str = r#"# Rust Visual C++ prerequisites
308+
309+
Rust requires a linker and Windows API libraries but they don't seem to be avaliable.
310+
311+
These components can be acquired by installing Visual Studio.
312+
313+
"#;
314+
302315
static UPDATE_ROOT: &str = "https://static.rust-lang.org/rustup";
303316

304317
/// `CARGO_HOME` suitable for display, possibly with $HOME
@@ -353,11 +366,26 @@ pub(crate) fn install(
353366
let mut term = term2::stdout();
354367

355368
#[cfg(windows)]
356-
if !do_msvc_check(&opts) {
369+
if let Some(plan) = do_msvc_check(&opts) {
357370
if no_prompt {
358371
warn!("installing msvc toolchain without its prerequisites");
359-
} else {
372+
} else if plan == VsInstallPlan::Automatic {
373+
md(&mut term, MSVC_AUTO_INSTALL_MESSAGE);
374+
if common::confirm(
375+
"Automatically download and install Visual Studio 2022 Community edition? (Y/n)",
376+
true,
377+
)? {
378+
try_install_msvc()?;
379+
} else {
380+
md(&mut term, MSVC_MANUAL_INSTALL_MESSAGE);
381+
if !common::confirm("\nContinue? (y/N)", false)? {
382+
info!("aborting installation");
383+
return Ok(utils::ExitCode(0));
384+
}
385+
}
386+
} else if plan == VsInstallPlan::Manual {
360387
md(&mut term, MSVC_MESSAGE);
388+
md(&mut term, MSVC_MANUAL_INSTALL_MESSAGE);
361389
if !common::confirm("\nContinue? (y/N)", false)? {
362390
info!("aborting installation");
363391
return Ok(utils::ExitCode(0));

src/cli/self_update/windows.rs

Lines changed: 104 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
use std::env::consts::EXE_SUFFIX;
1+
use std::env::{consts::EXE_SUFFIX, split_paths};
22
use std::ffi::{OsStr, OsString};
3+
use std::fmt;
34
use std::os::windows::ffi::{OsStrExt, OsStringExt};
45
use std::path::Path;
56
use std::process::Command;
@@ -24,12 +25,18 @@ pub(crate) fn ensure_prompt() -> Result<()> {
2425
Ok(())
2526
}
2627

28+
#[derive(PartialEq, Eq)]
29+
pub(crate) enum VsInstallPlan {
30+
Automatic,
31+
Manual,
32+
}
33+
2734
// Provide guidance about setting up MSVC if it doesn't appear to be
2835
// installed
29-
pub(crate) fn do_msvc_check(opts: &InstallOpts<'_>) -> bool {
36+
pub(crate) fn do_msvc_check(opts: &InstallOpts<'_>) -> Option<VsInstallPlan> {
3037
// Test suite skips this since it's env dependent
3138
if process().var("RUSTUP_INIT_SKIP_MSVC_CHECK").is_ok() {
32-
return true;
39+
return None;
3340
}
3441

3542
use cc::windows_registry;
@@ -41,10 +48,102 @@ pub(crate) fn do_msvc_check(opts: &InstallOpts<'_>) -> bool {
4148
let installing_msvc = host_triple.contains("msvc");
4249
let have_msvc = windows_registry::find_tool(&host_triple, "cl.exe").is_some();
4350
if installing_msvc && !have_msvc {
44-
return false;
51+
// Visual Studio build tools are required.
52+
// If the user does not have Visual Studio installed and their host
53+
// machine is i686 or x86_64 then it's OK to try an auto install.
54+
// Otherwise a manual install will be required.
55+
let has_any_vs = windows_registry::find_vs_version().is_ok();
56+
let is_x86 = host_triple.contains("i686") || host_triple.contains("x86_64");
57+
if is_x86 && !has_any_vs {
58+
Some(VsInstallPlan::Automatic)
59+
} else {
60+
Some(VsInstallPlan::Manual)
61+
}
62+
} else {
63+
None
64+
}
65+
}
66+
67+
#[derive(Debug)]
68+
struct VsInstallError(i32);
69+
impl std::error::Error for VsInstallError {}
70+
impl fmt::Display for VsInstallError {
71+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72+
// See https://docs.microsoft.com/en-us/visualstudio/install/use-command-line-parameters-to-install-visual-studio?view=vs-2022#error-codes
73+
let message = match self.0 {
74+
740 => "elevation required",
75+
1001 => "Visual Studio installer process is running",
76+
1003 => "Visual Studio is in use",
77+
1602 => "operation was canceled",
78+
1618 => "another installation running",
79+
1641 => "operation completed successfully, and reboot was initiated",
80+
3010 => "operation completed successfully, but install requires reboot before it can be used",
81+
5003 => "bootstrapper failed to download installer",
82+
5004 => "operation was canceled",
83+
5005 => "bootstrapper command-line parse error",
84+
5007 => "operation was blocked - the computer does not meet the requirements",
85+
8001 => "arm machine check failure",
86+
8002 => "background download precheck failure",
87+
8003 => "out of support selectable failure",
88+
8004 => "target directory failure",
89+
8005 => "verifying source payloads failure",
90+
8006 => "Visual Studio processes running",
91+
-1073720687 => "connectivity failure",
92+
-1073741510 => "Microsoft Visual Studio Installer was terminated",
93+
_ => "error installing Visual Studio"
94+
};
95+
write!(f, "{} (exit code {})", message, self.0)
4596
}
97+
}
4698

47-
true
99+
pub(crate) fn try_install_msvc() -> Result<()> {
100+
// download the installer
101+
let visual_studio_url = utils::parse_url("https://aka.ms/vs/17/release/vs_community.exe")?;
102+
103+
let tempdir = tempfile::Builder::new()
104+
.prefix("rustup-visualstudio")
105+
.tempdir()
106+
.context("error creating temp directory")?;
107+
108+
let visual_studio = tempdir.path().join("vs_setup.exe");
109+
utils::download_file(&visual_studio_url, &visual_studio, None, &|_| ())?;
110+
111+
// Run the installer. Arguments are documented at:
112+
// https://docs.microsoft.com/en-us/visualstudio/install/use-command-line-parameters-to-install-visual-studio
113+
let mut cmd = Command::new(visual_studio);
114+
cmd.arg("--wait")
115+
// Display an interactive GUI focused on installing just the selected components.
116+
.arg("--focusedUi")
117+
// Add the linker and C runtime libraries.
118+
.args(["--add", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64"]);
119+
120+
// It's possible an earlier or later version of the Windows SDK has been
121+
// installed separately from Visual Studio so installing it can be skipped.
122+
let mut has_libs = false;
123+
if let Some(paths) = process().var_os("lib") {
124+
for mut path in split_paths(&paths) {
125+
path.push("kernel32.lib");
126+
if path.exists() {
127+
has_libs = true;
128+
}
129+
}
130+
};
131+
if !has_libs {
132+
cmd.args([
133+
"--add",
134+
"Microsoft.VisualStudio.Component.Windows11SDK.22000",
135+
]);
136+
}
137+
let exit_status = cmd
138+
.spawn()
139+
.and_then(|mut child| child.wait())
140+
.context("error running Visual Studio installer")?;
141+
142+
if exit_status.success() {
143+
Ok(())
144+
} else {
145+
Err(VsInstallError(exit_status.code().unwrap())).context("failed to install Visual Studio")
146+
}
48147
}
49148

50149
/// Run by rustup-gc-$num.exe to delete CARGO_HOME

0 commit comments

Comments
 (0)