Make MSVC detection ludicrously robust
Should fix a few more edge cases Fixes https://github.com/rust-lang/rust/issues/31151 Fixes https://github.com/rust-lang/rust/issues/32159 Fixes https://github.com/rust-lang/rust/issues/34484 Improves https://github.com/rust-lang/rust-packaging/issues/50 Signed-off-by: Peter Atashian <retep998@gmail.com>
This commit is contained in:
parent
126af085be
commit
a1b33b4fdc
4 changed files with 261 additions and 182 deletions
|
@ -136,14 +136,17 @@ pub fn build_link_meta<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_linker(sess: &Session) -> (String, Command) {
|
// The third parameter is for an extra path to add to PATH for MSVC
|
||||||
|
// cross linkers for host toolchain DLL dependencies
|
||||||
|
pub fn get_linker(sess: &Session) -> (String, Command, Option<PathBuf>) {
|
||||||
if let Some(ref linker) = sess.opts.cg.linker {
|
if let Some(ref linker) = sess.opts.cg.linker {
|
||||||
(linker.clone(), Command::new(linker))
|
(linker.clone(), Command::new(linker), None)
|
||||||
} else if sess.target.target.options.is_like_msvc {
|
} else if sess.target.target.options.is_like_msvc {
|
||||||
("link.exe".to_string(), msvc::link_exe_cmd(sess))
|
let (cmd, host) = msvc::link_exe_cmd(sess);
|
||||||
|
("link.exe".to_string(), cmd, host)
|
||||||
} else {
|
} else {
|
||||||
(sess.target.target.options.linker.clone(),
|
(sess.target.target.options.linker.clone(),
|
||||||
Command::new(&sess.target.target.options.linker))
|
Command::new(&sess.target.target.options.linker), None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +156,7 @@ pub fn get_ar_prog(sess: &Session) -> String {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn command_path(sess: &Session) -> OsString {
|
fn command_path(sess: &Session, extra: Option<PathBuf>) -> OsString {
|
||||||
// The compiler's sysroot often has some bundled tools, so add it to the
|
// The compiler's sysroot often has some bundled tools, so add it to the
|
||||||
// PATH for the child.
|
// PATH for the child.
|
||||||
let mut new_path = sess.host_filesearch(PathKind::All)
|
let mut new_path = sess.host_filesearch(PathKind::All)
|
||||||
|
@ -161,9 +164,7 @@ fn command_path(sess: &Session) -> OsString {
|
||||||
if let Some(path) = env::var_os("PATH") {
|
if let Some(path) = env::var_os("PATH") {
|
||||||
new_path.extend(env::split_paths(&path));
|
new_path.extend(env::split_paths(&path));
|
||||||
}
|
}
|
||||||
if sess.target.target.options.is_like_msvc {
|
new_path.extend(extra);
|
||||||
new_path.extend(msvc::host_dll_path());
|
|
||||||
}
|
|
||||||
env::join_paths(new_path).unwrap()
|
env::join_paths(new_path).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,7 +380,7 @@ fn archive_config<'a>(sess: &'a Session,
|
||||||
src: input.map(|p| p.to_path_buf()),
|
src: input.map(|p| p.to_path_buf()),
|
||||||
lib_search_paths: archive_search_paths(sess),
|
lib_search_paths: archive_search_paths(sess),
|
||||||
ar_prog: get_ar_prog(sess),
|
ar_prog: get_ar_prog(sess),
|
||||||
command_path: command_path(sess),
|
command_path: command_path(sess, None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -616,8 +617,8 @@ fn link_natively(sess: &Session,
|
||||||
info!("preparing {:?} from {:?} to {:?}", crate_type, objects, out_filename);
|
info!("preparing {:?} from {:?} to {:?}", crate_type, objects, out_filename);
|
||||||
|
|
||||||
// The invocations of cc share some flags across platforms
|
// The invocations of cc share some flags across platforms
|
||||||
let (pname, mut cmd) = get_linker(sess);
|
let (pname, mut cmd, extra) = get_linker(sess);
|
||||||
cmd.env("PATH", command_path(sess));
|
cmd.env("PATH", command_path(sess, extra));
|
||||||
|
|
||||||
let root = sess.target_filesearch(PathKind::Native).get_lib_path();
|
let root = sess.target_filesearch(PathKind::Native).get_lib_path();
|
||||||
cmd.args(&sess.target.target.options.pre_link_args);
|
cmd.args(&sess.target.target.options.pre_link_args);
|
||||||
|
@ -682,10 +683,15 @@ fn link_natively(sess: &Session,
|
||||||
info!("linker stdout:\n{}", escape_string(&prog.stdout[..]));
|
info!("linker stdout:\n{}", escape_string(&prog.stdout[..]));
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// Trying to diagnose https://github.com/rust-lang/rust/issues/33844
|
|
||||||
sess.struct_err(&format!("could not exec the linker `{}`: {}", pname, e))
|
sess.struct_err(&format!("could not exec the linker `{}`: {}", pname, e))
|
||||||
.note(&format!("{:?}", &cmd))
|
.note(&format!("{:?}", &cmd))
|
||||||
.emit();
|
.emit();
|
||||||
|
if sess.target.target.options.is_like_msvc && e.kind() == io::ErrorKind::NotFound {
|
||||||
|
sess.note_without_error("the msvc targets depend on the msvc linker \
|
||||||
|
but `link.exe` was not found");
|
||||||
|
sess.note_without_error("please ensure that VS 2013 or VS 2015 was installed \
|
||||||
|
with the Visual C++ option");
|
||||||
|
}
|
||||||
sess.abort_if_errors();
|
sess.abort_if_errors();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
56
src/librustc_trans/back/msvc/arch.rs
Normal file
56
src/librustc_trans/back/msvc/arch.rs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
// Copyright 2016 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
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![allow(non_camel_case_types, non_snake_case)]
|
||||||
|
|
||||||
|
use libc::c_void;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
type DWORD = u32;
|
||||||
|
type WORD = u16;
|
||||||
|
type LPVOID = *mut c_void;
|
||||||
|
type DWORD_PTR = usize;
|
||||||
|
|
||||||
|
const PROCESSOR_ARCHITECTURE_INTEL: WORD = 0;
|
||||||
|
const PROCESSOR_ARCHITECTURE_AMD64: WORD = 9;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct SYSTEM_INFO {
|
||||||
|
wProcessorArchitecture: WORD,
|
||||||
|
_wReserved: WORD,
|
||||||
|
_dwPageSize: DWORD,
|
||||||
|
_lpMinimumApplicationAddress: LPVOID,
|
||||||
|
_lpMaximumApplicationAddress: LPVOID,
|
||||||
|
_dwActiveProcessorMask: DWORD_PTR,
|
||||||
|
_dwNumberOfProcessors: DWORD,
|
||||||
|
_dwProcessorType: DWORD,
|
||||||
|
_dwAllocationGranularity: DWORD,
|
||||||
|
_wProcessorLevel: WORD,
|
||||||
|
_wProcessorRevision: WORD,
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "system" {
|
||||||
|
fn GetNativeSystemInfo(lpSystemInfo: *mut SYSTEM_INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Arch {
|
||||||
|
X86,
|
||||||
|
Amd64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn host_arch() -> Option<Arch> {
|
||||||
|
let mut info = unsafe { mem::zeroed() };
|
||||||
|
unsafe { GetNativeSystemInfo(&mut info) };
|
||||||
|
match info.wProcessorArchitecture {
|
||||||
|
PROCESSOR_ARCHITECTURE_INTEL => Some(Arch::X86),
|
||||||
|
PROCESSOR_ARCHITECTURE_AMD64 => Some(Arch::Amd64),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,8 +31,18 @@
|
||||||
//! paths/files is based on Microsoft's logic in their vcvars bat files, but
|
//! paths/files is based on Microsoft's logic in their vcvars bat files, but
|
||||||
//! comments can also be found below leading through the various code paths.
|
//! comments can also be found below leading through the various code paths.
|
||||||
|
|
||||||
|
// A simple macro to make this option mess easier to read
|
||||||
|
macro_rules! otry {
|
||||||
|
($expr:expr) => (match $expr {
|
||||||
|
Some(val) => val,
|
||||||
|
None => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
mod registry;
|
mod registry;
|
||||||
|
#[cfg(windows)]
|
||||||
|
mod arch;
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
mod platform {
|
mod platform {
|
||||||
|
@ -42,111 +52,134 @@ mod platform {
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use session::Session;
|
use session::Session;
|
||||||
use super::registry::{LOCAL_MACHINE};
|
use super::arch::{host_arch, Arch};
|
||||||
|
use super::registry::LOCAL_MACHINE;
|
||||||
|
|
||||||
// Cross toolchains depend on dlls from the host toolchain
|
// First we need to figure out whether the environment is already correctly
|
||||||
// We can't just add it to the Command's PATH in `link_exe_cmd` because it
|
// configured by vcvars. We do this by looking at the environment variable
|
||||||
// is later overridden so we publicly expose it here instead
|
// `VCINSTALLDIR` which is always set by vcvars, and unlikely to be set
|
||||||
pub fn host_dll_path() -> Option<PathBuf> {
|
// otherwise. If it is defined, then we find `link.exe` in `PATH and trust
|
||||||
get_vc_dir().and_then(|(_, vcdir)| {
|
// that everything else is configured correctly.
|
||||||
host_dll_subdir().map(|sub| {
|
//
|
||||||
vcdir.join("bin").join(sub)
|
// If `VCINSTALLDIR` wasn't defined (or we couldn't find the linker where
|
||||||
|
// it claimed it should be), then we resort to finding everything
|
||||||
|
// ourselves. First we find where the latest version of MSVC is installed
|
||||||
|
// and what version it is. Then based on the version we find the
|
||||||
|
// appropriate SDKs.
|
||||||
|
//
|
||||||
|
// If despite our best efforts we are still unable to find MSVC then we
|
||||||
|
// just blindly call `link.exe` and hope for the best.
|
||||||
|
//
|
||||||
|
// This code only supports VC 11 through 15. For versions older than that
|
||||||
|
// the user will need to manually execute the appropriate vcvars bat file
|
||||||
|
// and it should hopefully work.
|
||||||
|
//
|
||||||
|
// The second member of the tuple we return is the directory for the host
|
||||||
|
// linker toolchain, which is necessary when using the cross linkers.
|
||||||
|
pub fn link_exe_cmd(sess: &Session) -> (Command, Option<PathBuf>) {
|
||||||
|
let arch = &sess.target.target.arch;
|
||||||
|
env::var_os("VCINSTALLDIR").and_then(|_| {
|
||||||
|
debug!("Detected that vcvars was already run.");
|
||||||
|
let path = otry!(env::var_os("PATH"));
|
||||||
|
// Mingw has its own link which is not the link we want so we
|
||||||
|
// look for `cl.exe` too as a precaution.
|
||||||
|
env::split_paths(&path).find(|path| {
|
||||||
|
path.join("cl.exe").is_file()
|
||||||
|
&& path.join("link.exe").is_file()
|
||||||
|
}).map(|path| {
|
||||||
|
(Command::new(path.join("link.exe")), None)
|
||||||
})
|
})
|
||||||
|
}).or_else(|| {
|
||||||
|
None.or_else(|| {
|
||||||
|
find_msvc_latest(arch, "15.0")
|
||||||
|
}).or_else(|| {
|
||||||
|
find_msvc_latest(arch, "14.0")
|
||||||
|
}).or_else(|| {
|
||||||
|
find_msvc_12(arch)
|
||||||
|
}).or_else(|| {
|
||||||
|
find_msvc_11(arch)
|
||||||
|
}).map(|(cmd, path)| (cmd, Some(path)))
|
||||||
|
}).unwrap_or_else(|| {
|
||||||
|
debug!("Failed to locate linker.");
|
||||||
|
(Command::new("link.exe"), None)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn link_exe_cmd(sess: &Session) -> Command {
|
// For MSVC 14 or newer we need to find the Universal CRT as well as either
|
||||||
let arch = &sess.target.target.arch;
|
// the Windows 10 SDK or Windows 8.1 SDK.
|
||||||
let (binsub, libsub, vclibsub) =
|
fn find_msvc_latest(arch: &str, ver: &str) -> Option<(Command, PathBuf)> {
|
||||||
match (bin_subdir(arch), lib_subdir(arch), vc_lib_subdir(arch)) {
|
let vcdir = otry!(get_vc_dir(ver));
|
||||||
(Some(x), Some(y), Some(z)) => (x, y, z),
|
let (mut cmd, host) = otry!(get_linker(&vcdir, arch));
|
||||||
_ => return Command::new("link.exe"),
|
let sub = otry!(lib_subdir(arch));
|
||||||
};
|
let ucrt = otry!(get_ucrt_dir());
|
||||||
|
debug!("Found Universal CRT {:?}", ucrt);
|
||||||
// First we need to figure out whether the environment is already correctly
|
add_lib(&mut cmd, &ucrt.join("ucrt").join(sub));
|
||||||
// configured by vcvars. We do this by looking at the environment variable
|
if let Some(dir) = get_sdk10_dir() {
|
||||||
// `VCINSTALLDIR` which is always set by vcvars, and unlikely to be set
|
debug!("Found Win10 SDK {:?}", dir);
|
||||||
// otherwise. If it is defined, then we derive the path to `link.exe` from
|
add_lib(&mut cmd, &dir.join("um").join(sub));
|
||||||
// that and trust that everything else is configured correctly.
|
} else if let Some(dir) = get_sdk81_dir() {
|
||||||
//
|
debug!("Found Win8.1 SDK {:?}", dir);
|
||||||
// If `VCINSTALLDIR` wasn't defined (or we couldn't find the linker where it
|
add_lib(&mut cmd, &dir.join("um").join(sub));
|
||||||
// claimed it should be), then we resort to finding everything ourselves.
|
} else {
|
||||||
// First we find where the latest version of MSVC is installed and what
|
return None
|
||||||
// version it is. Then based on the version we find the appropriate SDKs.
|
}
|
||||||
//
|
Some((cmd, host))
|
||||||
// For MSVC 14 (VS 2015) we look for the Win10 SDK and failing that we look
|
|
||||||
// for the Win8.1 SDK. We also look for the Universal CRT.
|
|
||||||
//
|
|
||||||
// For MSVC 12 (VS 2013) we look for the Win8.1 SDK.
|
|
||||||
//
|
|
||||||
// For MSVC 11 (VS 2012) we look for the Win8 SDK.
|
|
||||||
//
|
|
||||||
// For all other versions the user has to execute the appropriate vcvars bat
|
|
||||||
// file themselves to configure the environment.
|
|
||||||
//
|
|
||||||
// If despite our best efforts we are still unable to find MSVC then we just
|
|
||||||
// blindly call `link.exe` and hope for the best.
|
|
||||||
return env::var_os("VCINSTALLDIR").and_then(|dir| {
|
|
||||||
debug!("Environment already configured by user. Assuming it works.");
|
|
||||||
let mut p = PathBuf::from(dir);
|
|
||||||
p.push("bin");
|
|
||||||
p.push(binsub);
|
|
||||||
p.push("link.exe");
|
|
||||||
if !p.is_file() { return None }
|
|
||||||
Some(Command::new(p))
|
|
||||||
}).or_else(|| {
|
|
||||||
get_vc_dir().and_then(|(ver, vcdir)| {
|
|
||||||
debug!("Found VC installation directory {:?}", vcdir);
|
|
||||||
let linker = vcdir.clone().join("bin").join(binsub).join("link.exe");
|
|
||||||
if !linker.is_file() { return None }
|
|
||||||
let mut cmd = Command::new(linker);
|
|
||||||
add_lib(&mut cmd, &vcdir.join("lib").join(vclibsub));
|
|
||||||
if ver == "14.0" {
|
|
||||||
if let Some(dir) = get_ucrt_dir() {
|
|
||||||
debug!("Found Universal CRT {:?}", dir);
|
|
||||||
add_lib(&mut cmd, &dir.join("ucrt").join(libsub));
|
|
||||||
}
|
|
||||||
if let Some(dir) = get_sdk10_dir() {
|
|
||||||
debug!("Found Win10 SDK {:?}", dir);
|
|
||||||
add_lib(&mut cmd, &dir.join("um").join(libsub));
|
|
||||||
} else if let Some(dir) = get_sdk81_dir() {
|
|
||||||
debug!("Found Win8.1 SDK {:?}", dir);
|
|
||||||
add_lib(&mut cmd, &dir.join("um").join(libsub));
|
|
||||||
}
|
|
||||||
} else if ver == "12.0" {
|
|
||||||
if let Some(dir) = get_sdk81_dir() {
|
|
||||||
debug!("Found Win8.1 SDK {:?}", dir);
|
|
||||||
add_lib(&mut cmd, &dir.join("um").join(libsub));
|
|
||||||
}
|
|
||||||
} else { // ver == "11.0"
|
|
||||||
if let Some(dir) = get_sdk8_dir() {
|
|
||||||
debug!("Found Win8 SDK {:?}", dir);
|
|
||||||
add_lib(&mut cmd, &dir.join("um").join(libsub));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(cmd)
|
|
||||||
})
|
|
||||||
}).unwrap_or_else(|| {
|
|
||||||
debug!("Failed to locate linker.");
|
|
||||||
Command::new("link.exe")
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
// A convenience function to make the above code simpler
|
|
||||||
|
// For MSVC 12 we need to find the Windows 8.1 SDK.
|
||||||
|
fn find_msvc_12(arch: &str) -> Option<(Command, PathBuf)> {
|
||||||
|
let vcdir = otry!(get_vc_dir("12.0"));
|
||||||
|
let (mut cmd, host) = otry!(get_linker(&vcdir, arch));
|
||||||
|
let sub = otry!(lib_subdir(arch));
|
||||||
|
let sdk81 = otry!(get_sdk81_dir());
|
||||||
|
debug!("Found Win8.1 SDK {:?}", sdk81);
|
||||||
|
add_lib(&mut cmd, &sdk81.join("um").join(sub));
|
||||||
|
Some((cmd, host))
|
||||||
|
}
|
||||||
|
|
||||||
|
// For MSVC 11 we need to find the Windows 8 SDK.
|
||||||
|
fn find_msvc_11(arch: &str) -> Option<(Command, PathBuf)> {
|
||||||
|
let vcdir = otry!(get_vc_dir("11.0"));
|
||||||
|
let (mut cmd, host) = otry!(get_linker(&vcdir, arch));
|
||||||
|
let sub = otry!(lib_subdir(arch));
|
||||||
|
let sdk8 = otry!(get_sdk8_dir());
|
||||||
|
debug!("Found Win8 SDK {:?}", sdk8);
|
||||||
|
add_lib(&mut cmd, &sdk8.join("um").join(sub));
|
||||||
|
Some((cmd, host))
|
||||||
|
}
|
||||||
|
|
||||||
|
// A convenience function to append library paths.
|
||||||
fn add_lib(cmd: &mut Command, lib: &Path) {
|
fn add_lib(cmd: &mut Command, lib: &Path) {
|
||||||
let mut arg: OsString = "/LIBPATH:".into();
|
let mut arg: OsString = "/LIBPATH:".into();
|
||||||
arg.push(lib);
|
arg.push(lib);
|
||||||
cmd.arg(arg);
|
cmd.arg(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// To find MSVC we look in a specific registry key for the newest of the
|
// Given a possible MSVC installation directory, we look for the linker and
|
||||||
// three versions that we support.
|
// then add the MSVC library path.
|
||||||
fn get_vc_dir() -> Option<(&'static str, PathBuf)> {
|
fn get_linker(path: &Path, arch: &str) -> Option<(Command, PathBuf)> {
|
||||||
LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\VisualStudio\SxS\VC7".as_ref())
|
debug!("Looking for linker in {:?}", path);
|
||||||
.ok().and_then(|key| {
|
bin_subdir(arch).into_iter().map(|(sub, host)| {
|
||||||
["14.0", "12.0", "11.0"].iter().filter_map(|ver| {
|
(path.join("bin").join(sub).join("link.exe"),
|
||||||
key.query_str(ver).ok().map(|p| (*ver, p.into()))
|
path.join("bin").join(host))
|
||||||
}).next()
|
}).filter(|&(ref path, _)| {
|
||||||
})
|
path.is_file()
|
||||||
|
}).map(|(path, host)| {
|
||||||
|
(Command::new(path), host)
|
||||||
|
}).filter_map(|(mut cmd, host)| {
|
||||||
|
let sub = otry!(vc_lib_subdir(arch));
|
||||||
|
add_lib(&mut cmd, &path.join("lib").join(sub));
|
||||||
|
Some((cmd, host))
|
||||||
|
}).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 = otry!(LOCAL_MACHINE
|
||||||
|
.open(r"SOFTWARE\Microsoft\VisualStudio\SxS\VC7".as_ref()).ok());
|
||||||
|
let path = otry!(key.query_str(ver).ok());
|
||||||
|
Some(path.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
// To find the Universal CRT we look in a specific registry key for where
|
// To find the Universal CRT we look in a specific registry key for where
|
||||||
|
@ -154,46 +187,42 @@ mod platform {
|
||||||
// find the newest version. While this sort of sorting isn't ideal, it is
|
// find the newest version. While this sort of sorting isn't ideal, it is
|
||||||
// what vcvars does so that's good enough for us.
|
// what vcvars does so that's good enough for us.
|
||||||
fn get_ucrt_dir() -> Option<PathBuf> {
|
fn get_ucrt_dir() -> Option<PathBuf> {
|
||||||
LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\Windows Kits\Installed Roots".as_ref())
|
let key = otry!(LOCAL_MACHINE
|
||||||
.ok().and_then(|key| {
|
.open(r"SOFTWARE\Microsoft\Windows Kits\Installed Roots".as_ref()).ok());
|
||||||
key.query_str("KitsRoot10").ok()
|
let root = otry!(key.query_str("KitsRoot10").ok());
|
||||||
}).and_then(|root| {
|
let readdir = otry!(fs::read_dir(Path::new(&root).join("lib")).ok());
|
||||||
fs::read_dir(Path::new(&root).join("Lib")).ok()
|
readdir.filter_map(|dir| {
|
||||||
}).and_then(|readdir| {
|
dir.ok()
|
||||||
let mut dirs: Vec<_> = readdir.filter_map(|dir| {
|
}).map(|dir| {
|
||||||
dir.ok()
|
dir.path()
|
||||||
}).map(|dir| {
|
}).filter(|dir| {
|
||||||
dir.path()
|
dir.components().last().and_then(|c| {
|
||||||
}).filter(|dir| {
|
c.as_os_str().to_str()
|
||||||
dir.components().last().and_then(|c| {
|
}).map(|c| {
|
||||||
c.as_os_str().to_str()
|
c.starts_with("10.") && dir.join("ucrt").is_dir()
|
||||||
}).map(|c| c.starts_with("10.")).unwrap_or(false)
|
}).unwrap_or(false)
|
||||||
}).collect();
|
}).max()
|
||||||
dirs.sort();
|
|
||||||
dirs.pop()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vcvars finds the correct version of the Windows 10 SDK by looking
|
// Vcvars finds the correct version of the Windows 10 SDK by looking
|
||||||
// for the include um/Windows.h because sometimes a given version will
|
// 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
|
// only have UCRT bits without the rest of the SDK. Since we only care about
|
||||||
// libraries and not includes, we just look for the folder `um` in the lib
|
// libraries and not includes, we instead look for `um\x64\kernel32.lib`.
|
||||||
// section. Like we do for the Universal CRT, we sort the possibilities
|
// 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.
|
// asciibetically to find the newest one as that is what vcvars does.
|
||||||
fn get_sdk10_dir() -> Option<PathBuf> {
|
fn get_sdk10_dir() -> Option<PathBuf> {
|
||||||
LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0".as_ref())
|
let key = otry!(LOCAL_MACHINE
|
||||||
.ok().and_then(|key| {
|
.open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0".as_ref()).ok());
|
||||||
key.query_str("InstallationFolder").ok()
|
let root = otry!(key.query_str("InstallationFolder").ok());
|
||||||
}).and_then(|root| {
|
let readdir = otry!(fs::read_dir(Path::new(&root).join("lib")).ok());
|
||||||
fs::read_dir(Path::new(&root).join("lib")).ok()
|
let mut dirs: Vec<_> = readdir.filter_map(|dir| dir.ok())
|
||||||
}).and_then(|readdir| {
|
.map(|dir| dir.path()).collect();
|
||||||
let mut dirs: Vec<_> = readdir.filter_map(|dir| dir.ok())
|
dirs.sort();
|
||||||
.map(|dir| dir.path()).collect();
|
dirs.into_iter().rev().filter(|dir| {
|
||||||
dirs.sort();
|
dir.join("um").join("x64").join("kernel32.lib").is_file()
|
||||||
dirs.into_iter().rev().filter(|dir| {
|
}).next()
|
||||||
dir.join("um").is_dir()
|
|
||||||
}).next()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interestingly there are several subdirectories, `win7` `win8` and
|
// Interestingly there are several subdirectories, `win7` `win8` and
|
||||||
|
@ -201,21 +230,17 @@ mod platform {
|
||||||
// applies to us. Note that if we were targetting kernel mode drivers
|
// applies to us. Note that if we were targetting kernel mode drivers
|
||||||
// instead of user mode applications, we would care.
|
// instead of user mode applications, we would care.
|
||||||
fn get_sdk81_dir() -> Option<PathBuf> {
|
fn get_sdk81_dir() -> Option<PathBuf> {
|
||||||
LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1".as_ref())
|
let key = otry!(LOCAL_MACHINE
|
||||||
.ok().and_then(|key| {
|
.open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1".as_ref()).ok());
|
||||||
key.query_str("InstallationFolder").ok()
|
let root = otry!(key.query_str("InstallationFolder").ok());
|
||||||
}).map(|root| {
|
Some(Path::new(&root).join("lib").join("winv6.3"))
|
||||||
Path::new(&root).join("lib").join("winv6.3")
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_sdk8_dir() -> Option<PathBuf> {
|
fn get_sdk8_dir() -> Option<PathBuf> {
|
||||||
LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0".as_ref())
|
let key = otry!(LOCAL_MACHINE
|
||||||
.ok().and_then(|key| {
|
.open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0".as_ref()).ok());
|
||||||
key.query_str("InstallationFolder").ok()
|
let root = otry!(key.query_str("InstallationFolder").ok());
|
||||||
}).map(|root| {
|
Some(Path::new(&root).join("lib").join("win8"))
|
||||||
Path::new(&root).join("lib").join("win8")
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// When choosing the linker toolchain to use, we have to choose the one
|
// When choosing the linker toolchain to use, we have to choose the one
|
||||||
|
@ -223,31 +248,27 @@ mod platform {
|
||||||
// where someone on 32-bit Windows is trying to cross compile to 64-bit and
|
// where someone on 32-bit Windows is trying to cross compile to 64-bit and
|
||||||
// it tries to invoke the native 64-bit linker which won't work.
|
// it tries to invoke the native 64-bit linker which won't work.
|
||||||
//
|
//
|
||||||
// FIXME - This currently functions based on the host architecture of rustc
|
// For the return value of this function, the first member of the tuple is
|
||||||
// itself but it should instead detect the bitness of the OS itself.
|
// the folder of the linker we will be invoking, while the second member
|
||||||
|
// is the folder of the host toolchain for that linker 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.
|
||||||
//
|
//
|
||||||
// FIXME - Figure out what happens when the host architecture is arm.
|
// FIXME - Figure out what happens when the host architecture is arm.
|
||||||
//
|
fn bin_subdir(arch: &str) -> Vec<(&'static str, &'static str)> {
|
||||||
// FIXME - Some versions of MSVC may not come with all these toolchains.
|
match (arch, host_arch()) {
|
||||||
// Consider returning an array of toolchains and trying them one at a time
|
("x86", Some(Arch::X86)) => vec![("", "")],
|
||||||
// until the linker is found.
|
("x86", Some(Arch::Amd64)) => vec![("amd64_x86", "amd64"), ("", "")],
|
||||||
fn bin_subdir(arch: &str) -> Option<&'static str> {
|
("x86_64", Some(Arch::X86)) => vec![("x86_amd64", "")],
|
||||||
if cfg!(target_arch = "x86_64") {
|
("x86_64", Some(Arch::Amd64)) => vec![("amd64", "amd64"), ("x86_amd64", "")],
|
||||||
match arch {
|
("arm", Some(Arch::X86)) => vec![("x86_arm", "")],
|
||||||
"x86" => Some("amd64_x86"),
|
("arm", Some(Arch::Amd64)) => vec![("amd64_arm", "amd64"), ("x86_arm", "")],
|
||||||
"x86_64" => Some("amd64"),
|
_ => vec![],
|
||||||
"arm" => Some("amd64_arm"),
|
}
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
} else if cfg!(target_arch = "x86") {
|
|
||||||
match arch {
|
|
||||||
"x86" => Some(""),
|
|
||||||
"x86_64" => Some("x86_amd64"),
|
|
||||||
"arm" => Some("x86_arm"),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
} else { None }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lib_subdir(arch: &str) -> Option<&'static str> {
|
fn lib_subdir(arch: &str) -> Option<&'static str> {
|
||||||
match arch {
|
match arch {
|
||||||
"x86" => Some("x86"),
|
"x86" => Some("x86"),
|
||||||
|
@ -256,6 +277,7 @@ mod platform {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MSVC's x86 libraries are not in a subfolder
|
// MSVC's x86 libraries are not in a subfolder
|
||||||
fn vc_lib_subdir(arch: &str) -> Option<&'static str> {
|
fn vc_lib_subdir(arch: &str) -> Option<&'static str> {
|
||||||
match arch {
|
match arch {
|
||||||
|
@ -265,11 +287,6 @@ mod platform {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn host_dll_subdir() -> Option<&'static str> {
|
|
||||||
if cfg!(target_arch = "x86_64") { Some("amd64") }
|
|
||||||
else if cfg!(target_arch = "x86") { Some("") }
|
|
||||||
else { None }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're not on Windows, then there's no registry to search through and MSVC
|
// If we're not on Windows, then there's no registry to search through and MSVC
|
||||||
|
@ -279,9 +296,9 @@ mod platform {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use session::Session;
|
use session::Session;
|
||||||
pub fn link_exe_cmd(_sess: &Session) -> Command {
|
pub fn link_exe_cmd(_sess: &Session) -> (Command, Option<PathBuf>) {
|
||||||
Command::new("link.exe")
|
(Command::new("link.exe"), None)
|
||||||
}
|
}
|
||||||
pub fn host_dll_path() -> Option<PathBuf> { None }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::platform::*;
|
pub use self::platform::*;
|
||||||
|
|
|
@ -970,7 +970,7 @@ fn run_work_multithreaded(sess: &Session,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
|
pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
|
||||||
let (pname, mut cmd) = get_linker(sess);
|
let (pname, mut cmd, _) = get_linker(sess);
|
||||||
|
|
||||||
cmd.arg("-c").arg("-o").arg(&outputs.path(OutputType::Object))
|
cmd.arg("-c").arg("-o").arg(&outputs.path(OutputType::Object))
|
||||||
.arg(&outputs.temp_path(OutputType::Assembly));
|
.arg(&outputs.temp_path(OutputType::Assembly));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue