Auto merge of #27250 - alexcrichton:ucrt, r=brson

Visual Studio 2015, recently released, includes the Universal CRT, a different
flavor than was provided before. The binaries and header files for this library
are included in new locations not previously known about by gcc-rs, and this
commit adds support for the necessary probing to find these.

Unfortunately there are no prior examples of this probing to be found in
frameworks like CMake or clang, so this is done is a bit of a sketchy method
today. It assumes that the installation is in a relatively standard format and
then blindly looks for the location of the UCRT. I'd love to switch this over to
using registry keys for probing, but I was currently unable to find such keys.

This should enable the compiler to work outside VS 2015 dev tools prompts.
This commit is contained in:
bors 2015-07-27 23:38:04 +00:00
commit 8b835572b9
2 changed files with 94 additions and 15 deletions

19
configure vendored
View File

@ -1176,9 +1176,14 @@ do
# munging and some probing here. We also look for the default # munging and some probing here. We also look for the default
# INCLUDE and LIB variables for MSVC so we can set those in the # INCLUDE and LIB variables for MSVC so we can set those in the
# build system as well. # build system as well.
install=$(reg QUERY \
'HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\14.0' \
-v InstallDir)
if [ -z "$install" ]; then
install=$(reg QUERY \ install=$(reg QUERY \
'HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\12.0' \ 'HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\12.0' \
-v InstallDir) -v InstallDir)
fi
need_ok "couldn't find visual studio install root" need_ok "couldn't find visual studio install root"
CFG_MSVC_ROOT=$(echo "$install" | grep InstallDir | sed 's/.*REG_SZ[ ]*//') CFG_MSVC_ROOT=$(echo "$install" | grep InstallDir | sed 's/.*REG_SZ[ ]*//')
CFG_MSVC_ROOT=$(dirname "$CFG_MSVC_ROOT") CFG_MSVC_ROOT=$(dirname "$CFG_MSVC_ROOT")
@ -1460,12 +1465,22 @@ do
msg "configuring LLVM with:" msg "configuring LLVM with:"
msg "$CMAKE_ARGS" msg "$CMAKE_ARGS"
case "$CFG_MSVC_ROOT" in
*14.0*)
generator="Visual Studio 14 2015"
;;
*12.0*)
generator="Visual Studio 12 2013"
;;
*)
err "can't determine generator for LLVM cmake"
;;
esac
case "$t" in case "$t" in
x86_64-*) x86_64-*)
generator="Visual Studio 12 2013 Win64" generator="$generator Win64"
;; ;;
i686-*) i686-*)
generator="Visual Studio 12 2013"
;; ;;
*) *)
err "can only build LLVM for x86 platforms" err "can only build LLVM for x86 platforms"

View File

@ -42,7 +42,8 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
use std::env; use std::env;
use std::ffi::OsString; use std::ffi::OsString;
use std::fs; use std::fs;
use std::path::PathBuf; use std::io;
use std::path::{Path, PathBuf};
use self::registry::{RegistryKey, LOCAL_MACHINE}; use self::registry::{RegistryKey, LOCAL_MACHINE};
// When finding the link.exe binary the 32-bit version is at the top level // When finding the link.exe binary the 32-bit version is at the top level
@ -103,9 +104,16 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
// VS shells, so we only want to start adding our own pieces if it's not // VS shells, so we only want to start adding our own pieces if it's not
// set. // set.
// //
// If we're adding our own pieces, then we need to add two primary // If we're adding our own pieces, then we need to add a few primary
// directories to the default search path for the linker. The first is in // directories to the default search path for the linker. The first is in
// the VS install direcotry and the next is the Windows SDK directory. // the VS install direcotry, the next is the Windows SDK directory, and the
// last is the possible UCRT installation directory.
//
// The UCRT is a recent addition to Visual Studio installs (2015 at the time
// of this writing), and it's in the normal windows SDK folder, but there
// apparently aren't registry keys pointing to it. As a result we detect the
// installation and then add it manually. This logic will probably need to
// be tweaked over time...
if env::var_os("LIB").is_none() { if env::var_os("LIB").is_none() {
if let Some(mut vs_install_dir) = vs_install_dir { if let Some(mut vs_install_dir) = vs_install_dir {
vs_install_dir.push("VC/lib"); vs_install_dir.push("VC/lib");
@ -113,6 +121,15 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
let mut arg = OsString::from("/LIBPATH:"); let mut arg = OsString::from("/LIBPATH:");
arg.push(&vs_install_dir); arg.push(&vs_install_dir);
cmd.arg(arg); cmd.arg(arg);
if let Some((ucrt_root, vers)) = ucrt_install_dir(&vs_install_dir) {
if let Some(arch) = windows_sdk_v8_subdir(sess) {
let mut arg = OsString::from("/LIBPATH:");
arg.push(ucrt_root.join("Lib").join(vers)
.join("ucrt").join(arch));
cmd.arg(arg);
}
}
} }
if let Some(path) = get_windows_sdk_lib_path(sess) { if let Some(path) = get_windows_sdk_lib_path(sess) {
let mut arg = OsString::from("/LIBPATH:"); let mut arg = OsString::from("/LIBPATH:");
@ -189,7 +206,7 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
return max_key return max_key
} }
fn get_windows_sdk_lib_path(sess: &Session) -> Option<PathBuf> { fn get_windows_sdk_path() -> Option<(PathBuf, usize)> {
let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows"; let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows";
let key = LOCAL_MACHINE.open(key.as_ref()); let key = LOCAL_MACHINE.open(key.as_ref());
let (n, k) = match key.ok().as_ref().and_then(max_version) { let (n, k) = match key.ok().as_ref().and_then(max_version) {
@ -199,10 +216,17 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
let mut parts = n.to_str().unwrap().trim_left_matches("v").splitn(2, "."); let mut parts = n.to_str().unwrap().trim_left_matches("v").splitn(2, ".");
let major = parts.next().unwrap().parse::<usize>().unwrap(); let major = parts.next().unwrap().parse::<usize>().unwrap();
let _minor = parts.next().unwrap().parse::<usize>().unwrap(); let _minor = parts.next().unwrap().parse::<usize>().unwrap();
let path = match k.query_str("InstallationFolder") { k.query_str("InstallationFolder").ok().map(|folder| {
Ok(p) => PathBuf::from(p).join("Lib"), (PathBuf::from(folder), major)
Err(..) => return None, })
}
fn get_windows_sdk_lib_path(sess: &Session) -> Option<PathBuf> {
let (mut path, major) = match get_windows_sdk_path() {
Some(p) => p,
None => return None,
}; };
path.push("Lib");
if major <= 7 { if major <= 7 {
// In Windows SDK 7.x, x86 libraries are directly in the Lib folder, // In Windows SDK 7.x, x86 libraries are directly in the Lib folder,
// x64 libraries are inside, and it's not necessary to link agains // x64 libraries are inside, and it's not necessary to link agains
@ -218,11 +242,9 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
// depend on the version of the OS you're targeting. By default // depend on the version of the OS you're targeting. By default
// choose the newest, which usually corresponds to the version of // choose the newest, which usually corresponds to the version of
// the OS you've installed the SDK on. // the OS you've installed the SDK on.
let extra = match &sess.target.target.arch[..] { let extra = match windows_sdk_v8_subdir(sess) {
"x86" => "x86", Some(e) => e,
"x86_64" => "x64", None => return None,
"arm" => "arm",
_ => return None,
}; };
["winv6.3", "win8", "win7"].iter().map(|p| path.join(p)).find(|part| { ["winv6.3", "win8", "win7"].iter().map(|p| path.join(p)).find(|part| {
fs::metadata(part).is_ok() fs::metadata(part).is_ok()
@ -231,6 +253,48 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
}) })
} }
} }
fn windows_sdk_v8_subdir(sess: &Session) -> Option<&'static str> {
match &sess.target.target.arch[..] {
"x86" => Some("x86"),
"x86_64" => Some("x64"),
"arm" => Some("arm"),
_ => return None,
}
}
fn ucrt_install_dir(vs_install_dir: &Path) -> Option<(PathBuf, String)> {
let is_vs_14 = vs_install_dir.iter().filter_map(|p| p.to_str()).any(|s| {
s == "Microsoft Visual Studio 14.0"
});
if !is_vs_14 {
return None
}
let key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots";
let sdk_dir = LOCAL_MACHINE.open(key.as_ref()).and_then(|p| {
p.query_str("KitsRoot10")
}).map(PathBuf::from);
let sdk_dir = match sdk_dir {
Ok(p) => p,
Err(..) => return None,
};
(move || -> io::Result<_> {
let mut max = None;
let mut max_s = None;
for entry in try!(fs::read_dir(&sdk_dir.join("Lib"))) {
let entry = try!(entry);
if let Ok(s) = entry.file_name().into_string() {
if let Ok(u) = s.replace(".", "").parse::<usize>() {
if Some(u) > max {
max = Some(u);
max_s = Some(s);
}
}
}
}
Ok(max_s.map(|m| (sdk_dir, m)))
})().ok().and_then(|x| x)
}
} }
#[cfg(not(windows))] #[cfg(not(windows))]