// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms.
//! A helper module to looking for windows-specific tools: //! 1. On Windows host, probe the Windows Registry if needed; //! 2. On non-Windows host, check specified environment variables.
/// Attempts to find a tool within an MSVC installation using the Windows /// registry as a point to search from. /// /// The `target` argument is the target that the tool should work for (e.g. /// compile or link for) and the `tool` argument is the tool to find (e.g. /// `cl.exe` or `link.exe`). /// /// This function will return `None` if the tool could not be found, or it will /// return `Some(cmd)` which represents a command that's ready to execute the /// tool with the appropriate environment variables set. /// /// Note that this function always returns `None` for non-MSVC targets. pubfn find(target: &str, tool: &str) -> Option<Command> {
find_tool(target, tool).map(|c| c.to_command())
}
/// Similar to the `find` function above, this function will attempt the same /// operation (finding a MSVC tool in a local install) but instead returns a /// `Tool` which may be introspected. pubfn find_tool(target: &str, tool: &str) -> Option<Tool> { // This logic is all tailored for MSVC, if we're not that then bail out // early. if !target.contains("msvc") { return None;
}
// Split the target to get the arch. let target = TargetArch(target.split_once('-')?.0);
// Looks like msbuild isn't located in the same location as other tools like // cl.exe and lib.exe. if tool.contains("msbuild") { return impl_::find_msbuild(target);
}
// Looks like devenv isn't located in the same location as other tools like // cl.exe and lib.exe. if tool.contains("devenv") { return impl_::find_devenv(target);
}
// Ok, if we're here, now comes the fun part of the probing. Default shells // or shells like MSYS aren't really configured to execute `cl.exe` and the // various compiler tools shipped as part of Visual Studio. Here we try to // first find the relevant tool, then we also have to be sure to fill in // environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that // the tool is actually usable.
/// A version of Visual Studio #[derive(Debug, PartialEq, Eq, Copy, Clone)] #[non_exhaustive] pubenum VsVers { /// Visual Studio 12 (2013)
Vs12, /// Visual Studio 14 (2015)
Vs14, /// Visual Studio 15 (2017)
Vs15, /// Visual Studio 16 (2019)
Vs16, /// Visual Studio 17 (2022)
Vs17,
}
/// Find the most recent installed version of Visual Studio /// /// This is used by the cmake crate to figure out the correct /// generator. pubfn find_vs_version() -> Result<VsVers, String> { match std::env::var("VisualStudioVersion") {
Ok(version) => match &version[..] { "17.0" => Ok(VsVers::Vs17), "16.0" => Ok(VsVers::Vs16), "15.0" => Ok(VsVers::Vs15), "14.0" => Ok(VsVers::Vs14), "12.0" => Ok(VsVers::Vs12),
vers => Err(format!( "\n\n\
unsupported or unknown VisualStudio version: {}\n\ if another version is installed consider running \
the appropriate vcvars script before building this \ crate\n\ ",
vers
)),
},
_ => { // Check for the presence of a specific registry key // that indicates visual studio is installed. if impl_::has_msbuild_version("17.0") {
Ok(VsVers::Vs17)
} elseif impl_::has_msbuild_version("16.0") {
Ok(VsVers::Vs16)
} elseif impl_::has_msbuild_version("15.0") {
Ok(VsVers::Vs15)
} elseif impl_::has_msbuild_version("14.0") {
Ok(VsVers::Vs14)
} elseif impl_::has_msbuild_version("12.0") {
Ok(VsVers::Vs12)
} else {
Err(format!( "\n\n\
couldn't determine visual studio generator\n\ if VisualStudio is installed, however, consider \
running the appropriate vcvars script before building \
this crate\n\ "
))
}
}
}
}
/// Windows Implementation. #[cfg(windows)] mod impl_ { usecrate::windows::com; usecrate::windows::registry::{RegistryKey, LOCAL_MACHINE}; usecrate::windows::setup_config::SetupConfiguration; usecrate::windows::vs_instances::{VsInstances, VswhereInstance}; usecrate::windows::windows_sys::{
FreeLibrary, GetMachineTypeAttributes, GetProcAddress, LoadLibraryA, UserEnabled, HMODULE,
IMAGE_FILE_MACHINE_AMD64, MACHINE_ATTRIBUTES, S_OK,
}; use std::convert::TryFrom; use std::env; use std::ffi::OsString; use std::fs::File; use std::io::Read; use std::iter; use std::mem; use std::path::{Path, PathBuf}; use std::process::Command; use std::str::FromStr; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Once;
/// Get a function pointer to a function in the library. /// SAFETY: The caller must ensure that the function signature matches the actual function. /// The easiest way to do this is to add an entry to windows_sys_no_link.list and use the /// generated function for `func_signature`. unsafefn get_proc_address<F>(&self, name: &[u8]) -> Option<F> { let symbol = unsafe { GetProcAddress(self.0, name.as_ptr() as _) };
symbol.map(|symbol| unsafe { mem::transmute_copy(&symbol) })
}
}
impl Drop for LibraryHandle { fn drop(&mutself) { unsafe { FreeLibrary(self.0) };
}
}
type GetMachineTypeAttributesFuncType = unsafeextern"system"fn(u16, *mut MACHINE_ATTRIBUTES) -> i32; const _: () = { // Ensure that our hand-written signature matches the actual function signature. // We can't use `GetMachineTypeAttributes` outside of a const scope otherwise we'll end up statically linking to // it, which will fail to load on older versions of Windows. let _: GetMachineTypeAttributesFuncType = GetMachineTypeAttributes;
};
fn is_amd64_emulation_supported_inner() -> Option<bool> { // GetMachineTypeAttributes is only available on Win11 22000+, so dynamically load it. let kernel32 = LibraryHandle::new(b"kernel32.dll\0")?; // SAFETY: GetMachineTypeAttributesFuncType is checked to match the real function signature. let get_machine_type_attributes = unsafe {
kernel32
.get_proc_address::<GetMachineTypeAttributesFuncType>(b"GetMachineTypeAttributes\0")
}?; letmut attributes = Default::default(); ifunsafe { get_machine_type_attributes(IMAGE_FILE_MACHINE_AMD64, &mut attributes) } == S_OK
{
Some((attributes & UserEnabled) != 0)
} else {
Some(false)
}
}
fn is_amd64_emulation_supported() -> bool { // TODO: Replace with a OnceLock once MSRV is 1.70. static LOAD_VALUE: Once = Once::new(); static IS_SUPPORTED: AtomicBool = AtomicBool::new(false);
// Using Relaxed ordering since the Once is providing synchronization.
LOAD_VALUE.call_once(|| {
IS_SUPPORTED.store(
is_amd64_emulation_supported_inner().unwrap_or(false),
Ordering::Relaxed,
);
});
IS_SUPPORTED.load(Ordering::Relaxed)
}
/// Checks to see if the `VSCMD_ARG_TGT_ARCH` environment variable matches the /// given target's arch. Returns `None` if the variable does not exist. fn is_vscmd_target(target: TargetArch<'_>) -> Option<bool> { let vscmd_arch = env::var("VSCMD_ARG_TGT_ARCH").ok()?; // Convert the Rust target arch to its VS arch equivalent. let arch = match target.into() { "x86_64" => "x64", "aarch64" | "arm64ec" => "arm64", "i686" | "i586" => "x86", "thumbv7a" => "arm", // An unrecognized arch.
_ => return Some(false),
};
Some(vscmd_arch == arch)
}
/// Attempt to find the tool using environment variables set by vcvars. pub(super) fn find_msvc_environment(tool: &str, target: TargetArch<'_>) -> Option<Tool> { // Early return if the environment doesn't contain a VC install. if env::var_os("VCINSTALLDIR").is_none() { return None;
} let vs_install_dir = env::var_os("VSINSTALLDIR")?.into();
// If the vscmd target differs from the requested target then // attempt to get the tool using the VS install directory. if is_vscmd_target(target) == Some(false) { // We will only get here with versions 15+.
tool_from_vs15plus_instance(tool, target, &vs_install_dir)
} else { // Fallback to simply using the current environment.
env::var_os("PATH")
.and_then(|path| {
env::split_paths(&path)
.map(|p| p.join(tool))
.find(|p| p.exists())
})
.map(|path| Tool::with_family(path, MSVC_FAMILY))
}
}
// In MSVC 15 (2017) MS once again changed the scheme for locating // the tooling. Now we must go through some COM interfaces, which // is super fun for Rust. // // Note that much of this logic can be found [online] wrt paths, COM, etc. // // [online]: https://blogs.msdn.microsoft.com/vcblog/2017/03/06/finding-the-visual-c-compiler-tools-in-visual-studio-2017/ // // Returns MSVC 15+ instances (15, 16 right now), the order should be consider undefined. // // However, on ARM64 this method doesn't work because VS Installer fails to register COM component on ARM64. // Hence, as the last resort we try to use vswhere.exe to list available instances. fn vs15plus_instances(target: TargetArch<'_>) -> Option<VsInstances> {
vs15plus_instances_using_com().or_else(|| vs15plus_instances_using_vswhere(target))
}
let vs_instances =
VsInstances::VswhereBased(VswhereInstance::try_from(&vswhere_output.stdout).ok()?);
Some(vs_instances)
}
// Inspired from official microsoft/vswhere ParseVersionString // i.e. at most four u16 numbers separated by '.' fn parse_version(version: &str) -> Option<Vec<u16>> {
version
.split('.')
.map(|chunk| u16::from_str(chunk).ok())
.collect()
}
pub(super) fn find_msvc_15plus(tool: &str, target: TargetArch<'_>) -> Option<Tool> { let iter = vs15plus_instances(target)?;
iter.into_iter()
.filter_map(|instance| { let version = parse_version(&instance.installation_version()?)?; let instance_path = instance.installation_path()?; let tool = tool_from_vs15plus_instance(tool, target, &instance_path)?;
Some((version, tool))
})
.max_by(|(a_version, _), (b_version, _)| a_version.cmp(b_version))
.map(|(_version, tool)| tool)
}
// While the paths to Visual Studio 2017's devenv and MSBuild could // potentially be retrieved from the registry, finding them via // SetupConfiguration has shown to be [more reliable], and is preferred // according to Microsoft. To help head off potential regressions though, // we keep the registry method as a fallback option. // // [more reliable]: https://github.com/rust-lang/cc-rs/pull/331 fn find_tool_in_vs15_path(tool: &str, target: TargetArch<'_>) -> Option<Tool> { letmut path = match vs15plus_instances(target) {
Some(instances) => instances
.into_iter()
.filter_map(|instance| instance.installation_path())
.map(|path| path.join(tool))
.find(|path| path.is_file()),
None => None,
};
if path.is_none() { let key = r"SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7";
path = LOCAL_MACHINE
.open(key.as_ref())
.ok()
.and_then(|key| key.query_str("15.0").ok())
.map(|path| PathBuf::from(path).join(tool))
.and_then(|path| if path.is_file() { Some(path) } else { None });
}
fn vs15plus_vc_paths(
target: TargetArch<'_>,
instance_path: &Path,
) -> Option<(PathBuf, PathBuf, PathBuf, PathBuf, Option<PathBuf>, PathBuf)> { let version = vs15plus_vc_read_version(instance_path)?;
let hosts = match host_arch() {
X86 => &["X86"],
X86_64 => &["X64"], // Starting with VS 17.4, there is a natively hosted compiler on ARM64: // https://devblogs.microsoft.com/visualstudio/arm64-visual-studio-is-officially-here/ // On older versions of VS, we use x64 if running under emulation is supported, // otherwise use x86.
AARCH64 => { if is_amd64_emulation_supported() {
&["ARM64", "X64", "X86"][..]
} else {
&["ARM64", "X86"]
}
}
_ => return None,
}; let target = lib_subdir(target)?; // The directory layout here is MSVC/bin/Host$host/$target/ let path = instance_path.join(r"VC\Tools\MSVC").join(version); // We use the first available host architecture that can build for the target let (host_path, host) = hosts.iter().find_map(|&x| { let candidate = path.join("bin").join(format!("Host{}", x)); if candidate.join(target).exists() {
Some((candidate, x))
} else {
None
}
})?; // This is the path to the toolchain for a particular target, running // on a given host let bin_path = host_path.join(target); // But! we also need PATH to contain the target directory for the host // architecture, because it contains dlls like mspdb140.dll compiled for // the host architecture. let host_dylib_path = host_path.join(host.to_lowercase()); let lib_path = path.join("lib").join(target); let alt_lib_path = (target == "arm64ec").then(|| path.join("lib").join("arm64ec")); let include_path = path.join("include");
Some((
path,
bin_path,
host_dylib_path,
lib_path,
alt_lib_path,
include_path,
))
}
fn vs15plus_vc_read_version(dir: &Path) -> Option<String> { // Try to open the default version file. letmut version_path: PathBuf =
dir.join(r"VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt"); letmut version_file = iflet Ok(f) = File::open(&version_path) {
f
} else { // If the default doesn't exist, search for other version files. // These are in the form Microsoft.VCToolsVersion.v143.default.txt // where `143` is any three decimal digit version number. // This sorts versions by lexical order and selects the highest version. letmut version_file = String::new();
version_path.pop(); for file in version_path.read_dir().ok()? { let name = file.ok()?.file_name(); let name = name.to_str()?; if name.starts_with("Microsoft.VCToolsVersion.v")
&& name.ends_with(".default.txt")
&& name > &version_file
{
version_file.replace_range(.., name);
}
} if version_file.is_empty() { return None;
}
version_path.push(version_file);
File::open(version_path).ok()?
};
// Get the version string from the file we found. letmut version = String::new();
version_file.read_to_string(&mut version).ok()?;
version.truncate(version.trim_end().len());
Some(version)
}
fn atl_paths(target: TargetArch<'_>, path: &Path) -> Option<(PathBuf, PathBuf)> { let atl_path = path.join("atlmfc"); let sub = lib_subdir(target)?; if atl_path.exists() {
Some((atl_path.join("lib").join(sub), atl_path.join("include")))
} else {
None
}
}
// For MSVC 14 we need to find the Universal CRT as well as either // the Windows 10 SDK or Windows 8.1 SDK. pub(super) fn find_msvc_14(tool: &str, target: TargetArch<'_>) -> Option<Tool> { let vcdir = get_vc_dir("14.0")?; letmut tool = get_tool(tool, &vcdir, target)?;
add_sdks(&mut tool, target)?;
Some(tool.into_tool())
}
fn add_sdks(tool: &mut MsvcTool, target: TargetArch<'_>) -> Option<()> { let sub = lib_subdir(target)?; let (ucrt, ucrt_version) = get_ucrt_dir()?;
let host = match host_arch() {
X86 => "x86",
X86_64 => "x64",
AARCH64 => "arm64",
_ => return None,
};
let ucrt_include = ucrt.join("include").join(&ucrt_version);
tool.include.push(ucrt_include.join("ucrt"));
let ucrt_lib = ucrt.join("lib").join(&ucrt_version);
tool.libs.push(ucrt_lib.join("ucrt").join(sub));
iflet Some((sdk, version)) = get_sdk10_dir() {
tool.path.push(sdk.join("bin").join(host)); let sdk_lib = sdk.join("lib").join(&version);
tool.libs.push(sdk_lib.join("um").join(sub)); let sdk_include = sdk.join("include").join(&version);
tool.include.push(sdk_include.join("um"));
tool.include.push(sdk_include.join("cppwinrt"));
tool.include.push(sdk_include.join("winrt"));
tool.include.push(sdk_include.join("shared"));
} elseiflet Some(sdk) = get_sdk81_dir() {
tool.path.push(sdk.join("bin").join(host)); let sdk_lib = sdk.join("lib").join("winv6.3");
tool.libs.push(sdk_lib.join("um").join(sub)); let sdk_include = sdk.join("include");
tool.include.push(sdk_include.join("um"));
tool.include.push(sdk_include.join("winrt"));
tool.include.push(sdk_include.join("shared"));
}
Some(())
}
// For MSVC 12 we need to find the Windows 8.1 SDK. pub(super) fn find_msvc_12(tool: &str, target: TargetArch<'_>) -> Option<Tool> { let vcdir = get_vc_dir("12.0")?; letmut tool = get_tool(tool, &vcdir, target)?; let sub = lib_subdir(target)?; let sdk81 = get_sdk81_dir()?;
tool.path.push(sdk81.join("bin").join(sub)); let sdk_lib = sdk81.join("lib").join("winv6.3");
tool.libs.push(sdk_lib.join("um").join(sub)); let sdk_include = sdk81.join("include");
tool.include.push(sdk_include.join("shared"));
tool.include.push(sdk_include.join("um"));
tool.include.push(sdk_include.join("winrt"));
Some(tool.into_tool())
}
// For MSVC 11 we need to find the Windows 8 SDK. pub(super) fn find_msvc_11(tool: &str, target: TargetArch<'_>) -> Option<Tool> { let vcdir = get_vc_dir("11.0")?; letmut tool = get_tool(tool, &vcdir, target)?; let sub = lib_subdir(target)?; let sdk8 = get_sdk8_dir()?;
tool.path.push(sdk8.join("bin").join(sub)); let sdk_lib = sdk8.join("lib").join("win8");
tool.libs.push(sdk_lib.join("um").join(sub)); let sdk_include = sdk8.join("include");
tool.include.push(sdk_include.join("shared"));
tool.include.push(sdk_include.join("um"));
tool.include.push(sdk_include.join("winrt"));
Some(tool.into_tool())
}
fn add_env(tool: &mut Tool, env: &str, paths: Vec<PathBuf>) { let prev = env::var_os(env).unwrap_or(OsString::new()); let prev = env::split_paths(&prev); let new = paths.into_iter().chain(prev);
tool.env
.push((env.to_string().into(), env::join_paths(new).unwrap()));
}
// Given a possible MSVC installation directory, we look for the linker and // then add the MSVC library path. fn get_tool(tool: &str, path: &Path, target: TargetArch<'_>) -> Option<MsvcTool> {
bin_subdir(target)
.into_iter()
.map(|(sub, host)| {
(
path.join("bin").join(sub).join(tool),
path.join("bin").join(host),
)
})
.filter(|(path, _)| path.is_file())
.map(|(path, host)| { letmut tool = MsvcTool::new(path);
tool.path.push(host);
tool
})
.filter_map(|mut tool| { let sub = vc_lib_subdir(target)?;
tool.libs.push(path.join("lib").join(sub));
tool.include.push(path.join("include")); let atlmfc_path = path.join("atlmfc"); if atlmfc_path.exists() {
tool.libs.push(atlmfc_path.join("lib").join(sub));
tool.include.push(atlmfc_path.join("include"));
}
Some(tool)
})
.next()
}
// To find MSVC we look in a specific registry key for the version we are // trying to find. fn get_vc_dir(ver: &str) -> Option<PathBuf> { let key = r"SOFTWARE\Microsoft\VisualStudio\SxS\VC7"; let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; let path = key.query_str(ver).ok()?;
Some(path.into())
}
// To find the Universal CRT we look in a specific registry key for where // all the Universal CRTs are located and then sort them asciibetically to // find the newest version. While this sort of sorting isn't ideal, it is // what vcvars does so that's good enough for us. // // Returns a pair of (root, version) for the ucrt dir if found fn get_ucrt_dir() -> Option<(PathBuf, String)> { let key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots"; let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; let root = key.query_str("KitsRoot10").ok()?; let readdir = Path::new(&root).join("lib").read_dir().ok()?; let max_libdir = readdir
.filter_map(|dir| dir.ok())
.map(|dir| dir.path())
.filter(|dir| {
dir.components()
.last()
.and_then(|c| c.as_os_str().to_str())
.map(|c| c.starts_with("10.") && dir.join("ucrt").is_dir())
.unwrap_or(false)
})
.max()?; let version = max_libdir.components().last().unwrap(); let version = version.as_os_str().to_str().unwrap().to_string();
Some((root.into(), version))
}
// Vcvars finds the correct version of the Windows 10 SDK by looking // for the include `um\Windows.h` because sometimes a given version will // only have UCRT bits without the rest of the SDK. Since we only care about // libraries and not includes, we instead look for `um\x64\kernel32.lib`. // Since the 32-bit and 64-bit libraries are always installed together we // only need to bother checking x64, making this code a tiny bit simpler. // Like we do for the Universal CRT, we sort the possibilities // asciibetically to find the newest one as that is what vcvars does. // Before doing that, we check the "WindowsSdkDir" and "WindowsSDKVersion" // environment variables set by vcvars to use the environment sdk version // if one is already configured. fn get_sdk10_dir() -> Option<(PathBuf, String)> { iflet (Ok(root), Ok(version)) = (env::var("WindowsSdkDir"), env::var("WindowsSDKVersion"))
{ return Some((root.into(), version.trim_end_matches('\\').to_string()));
}
let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0"; let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; let root = key.query_str("InstallationFolder").ok()?; let readdir = Path::new(&root).join("lib").read_dir().ok()?; letmut dirs = readdir
.filter_map(|dir| dir.ok())
.map(|dir| dir.path())
.collect::<Vec<_>>();
dirs.sort(); let dir = dirs
.into_iter()
.rev()
.filter(|dir| dir.join("um").join("x64").join("kernel32.lib").is_file())
.next()?; let version = dir.components().last().unwrap(); let version = version.as_os_str().to_str().unwrap().to_string();
Some((root.into(), version))
}
// Interestingly there are several subdirectories, `win7` `win8` and // `winv6.3`. Vcvars seems to only care about `winv6.3` though, so the same // applies to us. Note that if we were targeting kernel mode drivers // instead of user mode applications, we would care. fn get_sdk81_dir() -> Option<PathBuf> { let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1"; let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; let root = key.query_str("InstallationFolder").ok()?;
Some(root.into())
}
fn get_sdk8_dir() -> Option<PathBuf> { let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0"; let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; let root = key.query_str("InstallationFolder").ok()?;
Some(root.into())
}
// When choosing the tool to use, we have to choose the one which matches // the target architecture. Otherwise we end up in situations where someone // on 32-bit Windows is trying to cross compile to 64-bit and it tries to // invoke the native 64-bit compiler which won't work. // // For the return value of this function, the first member of the tuple is // the folder of the tool we will be invoking, while the second member is // the folder of the host toolchain for that tool which is essential when // using a cross linker. We return a Vec since on x64 there are often two // linkers that can target the architecture we desire. The 64-bit host // linker is preferred, and hence first, due to 64-bit allowing it more // address space to work with and potentially being faster. fn bin_subdir(target: TargetArch<'_>) -> Vec<(&'static str, &'static str)> { match (target.into(), host_arch()) {
("i586", X86) | ("i686", X86) => vec![("", "")],
("i586", X86_64) | ("i686", X86_64) => vec![("amd64_x86", "amd64"), ("", "")],
("x86_64", X86) => vec![("x86_amd64", "")],
("x86_64", X86_64) => vec![("amd64", "amd64"), ("x86_amd64", "")],
("arm", X86) | ("thumbv7a", X86) => vec![("x86_arm", "")],
("arm", X86_64) | ("thumbv7a", X86_64) => vec![("amd64_arm", "amd64"), ("x86_arm", "")],
_ => vec![],
}
}
// Given a registry key, look at all the sub keys and find the one which has // the maximal numeric value. // // Returns the name of the maximal key as well as the opened maximal key. fn max_version(key: &RegistryKey) -> Option<(OsString, RegistryKey)> { letmut max_vers = 0; letmut max_key = None; for subkey in key.iter().filter_map(|k| k.ok()) { let val = subkey
.to_str()
.and_then(|s| s.trim_left_matches("v").replace('.', "").parse().ok()); let val = match val {
Some(s) => s,
None => continue,
}; if val > max_vers { iflet Ok(k) = key.open(&subkey) {
max_vers = val;
max_key = Some((subkey, k));
}
}
}
max_key
}
/// Finding msbuild.exe tool under unix system is not currently supported. /// Maybe can check it using an environment variable looks like `MSBUILD_BIN`. pub(super) fn find_msbuild(_target: TargetArch<'_>) -> Option<Tool> {
None
}
// Finding devenv.exe tool under unix system is not currently supported. // Maybe can check it using an environment variable looks like `DEVENV_BIN`. pub(super) fn find_devenv(_target: TargetArch<'_>) -> Option<Tool> {
None
}
/// Attempt to find the tool using environment variables set by vcvars. pub(super) fn find_msvc_environment(tool: &str, _target: TargetArch<'_>) -> Option<Tool> { // Early return if the environment doesn't contain a VC install. let vc_install_dir = env::var_os("VCINSTALLDIR")?; let vs_install_dir = env::var_os("VSINSTALLDIR")?;
// Take the path of tool for the vc install directory.
get_tool(vc_install_dir) // Take the path of tool for the vs install directory.
.or_else(|| get_tool(vs_install_dir)) // Take the path of tool for the current path environment.
.or_else(|| env::var_os("PATH").and_then(|path| get_tool(path)))
}
// For MSVC 14 we need to find the Universal CRT as well as either // the Windows 10 SDK or Windows 8.1 SDK. pub(super) fn find_msvc_14(_tool: &str, _target: TargetArch<'_>) -> Option<Tool> {
None
}
// For MSVC 12 we need to find the Windows 8.1 SDK. pub(super) fn find_msvc_12(_tool: &str, _target: TargetArch<'_>) -> Option<Tool> {
None
}
// For MSVC 11 we need to find the Windows 8 SDK. pub(super) fn find_msvc_11(_tool: &str, _target: TargetArch<'_>) -> Option<Tool> {
None
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.