Skip to content

Commit 8b83557

Browse files
committed
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.
2 parents 75e4a78 + 7bb585d commit 8b83557

File tree

2 files changed

+94
-15
lines changed

2 files changed

+94
-15
lines changed

configure

+18-3
Original file line numberDiff line numberDiff line change
@@ -1177,8 +1177,13 @@ do
11771177
# INCLUDE and LIB variables for MSVC so we can set those in the
11781178
# build system as well.
11791179
install=$(reg QUERY \
1180-
'HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\12.0' \
1180+
'HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\14.0' \
11811181
-v InstallDir)
1182+
if [ -z "$install" ]; then
1183+
install=$(reg QUERY \
1184+
'HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\12.0' \
1185+
-v InstallDir)
1186+
fi
11821187
need_ok "couldn't find visual studio install root"
11831188
CFG_MSVC_ROOT=$(echo "$install" | grep InstallDir | sed 's/.*REG_SZ[ ]*//')
11841189
CFG_MSVC_ROOT=$(dirname "$CFG_MSVC_ROOT")
@@ -1460,12 +1465,22 @@ do
14601465

14611466
msg "configuring LLVM with:"
14621467
msg "$CMAKE_ARGS"
1468+
case "$CFG_MSVC_ROOT" in
1469+
*14.0*)
1470+
generator="Visual Studio 14 2015"
1471+
;;
1472+
*12.0*)
1473+
generator="Visual Studio 12 2013"
1474+
;;
1475+
*)
1476+
err "can't determine generator for LLVM cmake"
1477+
;;
1478+
esac
14631479
case "$t" in
14641480
x86_64-*)
1465-
generator="Visual Studio 12 2013 Win64"
1481+
generator="$generator Win64"
14661482
;;
14671483
i686-*)
1468-
generator="Visual Studio 12 2013"
14691484
;;
14701485
*)
14711486
err "can only build LLVM for x86 platforms"

src/librustc_trans/back/msvc/mod.rs

+76-12
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
4242
use std::env;
4343
use std::ffi::OsString;
4444
use std::fs;
45-
use std::path::PathBuf;
45+
use std::io;
46+
use std::path::{Path, PathBuf};
4647
use self::registry::{RegistryKey, LOCAL_MACHINE};
4748

4849
// When finding the link.exe binary the 32-bit version is at the top level
@@ -103,16 +104,32 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
103104
// VS shells, so we only want to start adding our own pieces if it's not
104105
// set.
105106
//
106-
// If we're adding our own pieces, then we need to add two primary
107+
// If we're adding our own pieces, then we need to add a few primary
107108
// directories to the default search path for the linker. The first is in
108-
// the VS install direcotry and the next is the Windows SDK directory.
109+
// the VS install direcotry, the next is the Windows SDK directory, and the
110+
// last is the possible UCRT installation directory.
111+
//
112+
// The UCRT is a recent addition to Visual Studio installs (2015 at the time
113+
// of this writing), and it's in the normal windows SDK folder, but there
114+
// apparently aren't registry keys pointing to it. As a result we detect the
115+
// installation and then add it manually. This logic will probably need to
116+
// be tweaked over time...
109117
if env::var_os("LIB").is_none() {
110118
if let Some(mut vs_install_dir) = vs_install_dir {
111119
vs_install_dir.push("VC/lib");
112120
vs_install_dir.push(extra);
113121
let mut arg = OsString::from("/LIBPATH:");
114122
arg.push(&vs_install_dir);
115123
cmd.arg(arg);
124+
125+
if let Some((ucrt_root, vers)) = ucrt_install_dir(&vs_install_dir) {
126+
if let Some(arch) = windows_sdk_v8_subdir(sess) {
127+
let mut arg = OsString::from("/LIBPATH:");
128+
arg.push(ucrt_root.join("Lib").join(vers)
129+
.join("ucrt").join(arch));
130+
cmd.arg(arg);
131+
}
132+
}
116133
}
117134
if let Some(path) = get_windows_sdk_lib_path(sess) {
118135
let mut arg = OsString::from("/LIBPATH:");
@@ -189,7 +206,7 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
189206
return max_key
190207
}
191208

192-
fn get_windows_sdk_lib_path(sess: &Session) -> Option<PathBuf> {
209+
fn get_windows_sdk_path() -> Option<(PathBuf, usize)> {
193210
let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows";
194211
let key = LOCAL_MACHINE.open(key.as_ref());
195212
let (n, k) = match key.ok().as_ref().and_then(max_version) {
@@ -199,10 +216,17 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
199216
let mut parts = n.to_str().unwrap().trim_left_matches("v").splitn(2, ".");
200217
let major = parts.next().unwrap().parse::<usize>().unwrap();
201218
let _minor = parts.next().unwrap().parse::<usize>().unwrap();
202-
let path = match k.query_str("InstallationFolder") {
203-
Ok(p) => PathBuf::from(p).join("Lib"),
204-
Err(..) => return None,
219+
k.query_str("InstallationFolder").ok().map(|folder| {
220+
(PathBuf::from(folder), major)
221+
})
222+
}
223+
224+
fn get_windows_sdk_lib_path(sess: &Session) -> Option<PathBuf> {
225+
let (mut path, major) = match get_windows_sdk_path() {
226+
Some(p) => p,
227+
None => return None,
205228
};
229+
path.push("Lib");
206230
if major <= 7 {
207231
// In Windows SDK 7.x, x86 libraries are directly in the Lib folder,
208232
// x64 libraries are inside, and it's not necessary to link agains
@@ -218,11 +242,9 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
218242
// depend on the version of the OS you're targeting. By default
219243
// choose the newest, which usually corresponds to the version of
220244
// the OS you've installed the SDK on.
221-
let extra = match &sess.target.target.arch[..] {
222-
"x86" => "x86",
223-
"x86_64" => "x64",
224-
"arm" => "arm",
225-
_ => return None,
245+
let extra = match windows_sdk_v8_subdir(sess) {
246+
Some(e) => e,
247+
None => return None,
226248
};
227249
["winv6.3", "win8", "win7"].iter().map(|p| path.join(p)).find(|part| {
228250
fs::metadata(part).is_ok()
@@ -231,6 +253,48 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
231253
})
232254
}
233255
}
256+
257+
fn windows_sdk_v8_subdir(sess: &Session) -> Option<&'static str> {
258+
match &sess.target.target.arch[..] {
259+
"x86" => Some("x86"),
260+
"x86_64" => Some("x64"),
261+
"arm" => Some("arm"),
262+
_ => return None,
263+
}
264+
}
265+
266+
fn ucrt_install_dir(vs_install_dir: &Path) -> Option<(PathBuf, String)> {
267+
let is_vs_14 = vs_install_dir.iter().filter_map(|p| p.to_str()).any(|s| {
268+
s == "Microsoft Visual Studio 14.0"
269+
});
270+
if !is_vs_14 {
271+
return None
272+
}
273+
let key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots";
274+
let sdk_dir = LOCAL_MACHINE.open(key.as_ref()).and_then(|p| {
275+
p.query_str("KitsRoot10")
276+
}).map(PathBuf::from);
277+
let sdk_dir = match sdk_dir {
278+
Ok(p) => p,
279+
Err(..) => return None,
280+
};
281+
(move || -> io::Result<_> {
282+
let mut max = None;
283+
let mut max_s = None;
284+
for entry in try!(fs::read_dir(&sdk_dir.join("Lib"))) {
285+
let entry = try!(entry);
286+
if let Ok(s) = entry.file_name().into_string() {
287+
if let Ok(u) = s.replace(".", "").parse::<usize>() {
288+
if Some(u) > max {
289+
max = Some(u);
290+
max_s = Some(s);
291+
}
292+
}
293+
}
294+
}
295+
Ok(max_s.map(|m| (sdk_dir, m)))
296+
})().ok().and_then(|x| x)
297+
}
234298
}
235299

236300
#[cfg(not(windows))]

0 commit comments

Comments
 (0)