Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Offer to auto install VS 2022 #2954

Merged
merged 4 commits into from
Mar 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions src/cli/self_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,11 @@ static MSVC_MESSAGE: &str = r#"# Rust Visual C++ prerequisites
Rust requires the Microsoft C++ build tools for Visual Studio 2013 or
later, but they don't seem to be installed.
The easiest way to acquire the build tools is by installing Microsoft
"#;

#[cfg(windows)]
static MSVC_MANUAL_INSTALL_MESSAGE: &str = r#"
You can acquire the build tools by installing Microsoft
Visual C++ Build Tools 2019 which provides just the Visual C++ build
tools:
Expand All @@ -299,6 +303,15 @@ doing then it is fine to continue installation without the build
tools, but otherwise, install the C++ build tools before proceeding.
"#;

#[cfg(windows)]
static MSVC_AUTO_INSTALL_MESSAGE: &str = r#"# Rust Visual C++ prerequisites
Rust requires a linker and Windows API libraries but they don't seem to be avaliable.
These components can be acquired by installing Visual Studio.
"#;

static UPDATE_ROOT: &str = "https://static.rust-lang.org/rustup";

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

#[cfg(windows)]
if !do_msvc_check(&opts) {
if let Some(plan) = do_msvc_check(&opts) {
if no_prompt {
warn!("installing msvc toolchain without its prerequisites");
} else if !quiet && plan == VsInstallPlan::Automatic {
md(&mut term, MSVC_AUTO_INSTALL_MESSAGE);
if common::confirm(
"\nAutomatically download and install Visual Studio 2022 Community edition? (Y/n)",
true,
)? {
try_install_msvc()?;
} else {
md(&mut term, MSVC_MANUAL_INSTALL_MESSAGE);
if !common::confirm("\nContinue? (y/N)", false)? {
info!("aborting installation");
return Ok(utils::ExitCode(0));
}
}
} else {
md(&mut term, MSVC_MESSAGE);
md(&mut term, MSVC_MANUAL_INSTALL_MESSAGE);
if !common::confirm("\nContinue? (y/N)", false)? {
info!("aborting installation");
return Ok(utils::ExitCode(0));
Expand Down
123 changes: 118 additions & 5 deletions src/cli/self_update/windows.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::env::consts::EXE_SUFFIX;
use std::cell::RefCell;
use std::env::{consts::EXE_SUFFIX, split_paths};
use std::ffi::{OsStr, OsString};
use std::fmt;
use std::os::windows::ffi::{OsStrExt, OsStringExt};
use std::path::Path;
use std::process::Command;
Expand All @@ -9,6 +11,7 @@ use anyhow::{anyhow, Context, Result};
use super::super::errors::*;
use super::common;
use super::{install_bins, InstallOpts};
use crate::cli::download_tracker::DownloadTracker;
use crate::dist::dist::TargetTriple;
use crate::process;
use crate::utils::utils;
Expand All @@ -24,12 +27,18 @@ pub(crate) fn ensure_prompt() -> Result<()> {
Ok(())
}

#[derive(PartialEq, Eq)]
pub(crate) enum VsInstallPlan {
Automatic,
Manual,
}

// Provide guidance about setting up MSVC if it doesn't appear to be
// installed
pub(crate) fn do_msvc_check(opts: &InstallOpts<'_>) -> bool {
pub(crate) fn do_msvc_check(opts: &InstallOpts<'_>) -> Option<VsInstallPlan> {
// Test suite skips this since it's env dependent
if process().var("RUSTUP_INIT_SKIP_MSVC_CHECK").is_ok() {
return true;
return None;
}

use cc::windows_registry;
Expand All @@ -41,10 +50,114 @@ pub(crate) fn do_msvc_check(opts: &InstallOpts<'_>) -> bool {
let installing_msvc = host_triple.contains("msvc");
let have_msvc = windows_registry::find_tool(&host_triple, "cl.exe").is_some();
if installing_msvc && !have_msvc {
return false;
// Visual Studio build tools are required.
// If the user does not have Visual Studio installed and their host
// machine is i686 or x86_64 then it's OK to try an auto install.
// Otherwise a manual install will be required.
let has_any_vs = windows_registry::find_vs_version().is_ok();
let is_x86 = host_triple.contains("i686") || host_triple.contains("x86_64");
if is_x86 && !has_any_vs {
Some(VsInstallPlan::Automatic)
} else {
Some(VsInstallPlan::Manual)
}
} else {
None
}
}

#[derive(Debug)]
struct VsInstallError(i32);
impl std::error::Error for VsInstallError {}
impl fmt::Display for VsInstallError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// See https://docs.microsoft.com/en-us/visualstudio/install/use-command-line-parameters-to-install-visual-studio?view=vs-2022#error-codes
let message = match self.0 {
740 => "elevation required",
1001 => "Visual Studio installer process is running",
1003 => "Visual Studio is in use",
1602 => "operation was canceled",
1618 => "another installation running",
1641 => "operation completed successfully, and reboot was initiated",
3010 => "operation completed successfully, but install requires reboot before it can be used",
5003 => "bootstrapper failed to download installer",
5004 => "operation was canceled",
5005 => "bootstrapper command-line parse error",
5007 => "operation was blocked - the computer does not meet the requirements",
8001 => "arm machine check failure",
8002 => "background download precheck failure",
8003 => "out of support selectable failure",
8004 => "target directory failure",
8005 => "verifying source payloads failure",
8006 => "Visual Studio processes running",
-1073720687 => "connectivity failure",
-1073741510 => "Microsoft Visual Studio Installer was terminated",
_ => "error installing Visual Studio"
};
write!(f, "{} (exit code {})", message, self.0)
}
}

true
pub(crate) fn try_install_msvc() -> Result<()> {
// download the installer
let visual_studio_url = utils::parse_url("https://aka.ms/vs/17/release/vs_community.exe")?;

let tempdir = tempfile::Builder::new()
.prefix("rustup-visualstudio")
.tempdir()
.context("error creating temp directory")?;

let visual_studio = tempdir.path().join("vs_setup.exe");
let download_tracker = RefCell::new(DownloadTracker::new().with_display_progress(true));
download_tracker.borrow_mut().download_finished();

info!("downloading Visual Studio installer");
utils::download_file(&visual_studio_url, &visual_studio, None, &move |n| {
download_tracker
.borrow_mut()
.handle_notification(&crate::Notification::Install(
crate::dist::Notification::Utils(n),
));
})?;

// Run the installer. Arguments are documented at:
// https://docs.microsoft.com/en-us/visualstudio/install/use-command-line-parameters-to-install-visual-studio
let mut cmd = Command::new(visual_studio);
cmd.arg("--wait")
// Display an interactive GUI focused on installing just the selected components.
.arg("--focusedUi")
// Add the linker and C runtime libraries.
.args(["--add", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64"]);
kinnison marked this conversation as resolved.
Show resolved Hide resolved

// It's possible an earlier or later version of the Windows SDK has been
// installed separately from Visual Studio so installing it can be skipped.
let mut has_libs = false;
if let Some(paths) = process().var_os("lib") {
for mut path in split_paths(&paths) {
path.push("kernel32.lib");
if path.exists() {
has_libs = true;
}
}
};
if !has_libs {
cmd.args([
"--add",
"Microsoft.VisualStudio.Component.Windows11SDK.22000",
kinnison marked this conversation as resolved.
Show resolved Hide resolved
]);
}
info!("running the Visual Studio install");
info!("rustup will continue once Visual Studio installation is complete\n");
let exit_status = cmd
.spawn()
.and_then(|mut child| child.wait())
.context("error running Visual Studio installer")?;

if exit_status.success() {
Ok(())
} else {
Err(VsInstallError(exit_status.code().unwrap())).context("failed to install Visual Studio")
}
}

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