Browse Source

Try to detect the Universal CRT on MSVC installs

Visual Studio 2015, recently releases, 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 (for now).
add-rc-path
Alex Crichton 10 years ago
parent
commit
61a867013e
  1. 10
      appveyor.yml
  2. 38
      gcc-test/build.rs
  3. 13
      gcc-test/src/NMakefile
  4. 3
      gcc-test/src/lib.rs
  5. 7
      gcc-test/src/msvc.c
  6. 8
      gcc-test/tests/all.rs
  7. 41
      src/windows_registry.rs

10
appveyor.yml

@ -2,14 +2,22 @@ environment:
matrix:
- TARGET: x86_64-pc-windows-msvc
ARCH: amd64
VS: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat
- TARGET: x86_64-pc-windows-msvc
ARCH: amd64
VS: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat
- TARGET: i686-pc-windows-msvc
ARCH: x86
VS: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat
- TARGET: i686-pc-windows-msvc
ARCH: x86
VS: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat
- TARGET: i686-pc-windows-gnu
ARCH: x86
install:
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe"
- rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
- call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" %ARCH%
- if defined VS call "%VS%" %ARCH%
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
- SET PATH=%PATH%;C:\MinGW\bin
- rustc -V

38
gcc-test/build.rs

@ -1,6 +1,14 @@
extern crate gcc;
use std::env;
use std::fs;
use std::path::PathBuf;
fn main() {
let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
fs::remove_dir_all(&out).unwrap();
fs::create_dir(&out).unwrap();
gcc::Config::new()
.file("src/foo.c")
.define("FOO", None)
@ -31,4 +39,34 @@ fn main() {
.file("src/windows.c")
.compile("libwindows.a");
}
// Test that the `windows_registry` module will set PATH by looking for
// nmake which runs vanilla cl, and then also test it after we remove all
// the relevant env vars from our own process.
if target.contains("msvc") {
let out = out.join("tmp");
fs::create_dir(&out).unwrap();
let status = gcc::windows_registry::find(&target, "nmake.exe").unwrap()
.arg("/fsrc/NMakefile")
.env("OUT_DIR", &out)
.status()
.unwrap();
assert!(status.success());
fs::remove_dir_all(&out).unwrap();
fs::create_dir(&out).unwrap();
env::remove_var("PATH");
env::remove_var("VCINSTALLDIR");
env::remove_var("INCLUDE");
env::remove_var("LIB");
let status = gcc::windows_registry::find(&target, "nmake.exe").unwrap()
.arg("/fsrc/NMakefile")
.env("OUT_DIR", &out)
.status()
.unwrap();
assert!(status.success());
println!("cargo:rustc-link-lib=msvc");
println!("cargo:rustc-link-search={}", out.display());
}
}

13
gcc-test/src/NMakefile

@ -0,0 +1,13 @@
all: $(OUT_DIR)/msvc.lib $(OUT_DIR)/msvc.exe
$(OUT_DIR)/msvc.lib: $(OUT_DIR)/msvc.o
lib -nologo -out:$(OUT_DIR)/msvc.lib $(OUT_DIR)/msvc.o
$(OUT_DIR)/msvc.o: src/msvc.c
$(CC) -nologo -c -Fo:$@ src/msvc.c
$(OUT_DIR)/msvc.exe: $(OUT_DIR)/msvc2.o
$(CC) -nologo -Fo:$@ $(OUT_DIR)/msvc2.o
$(OUT_DIR)/msvc2.o: src/msvc.c
$(CC) -nologo -c -Fo:$@ src/msvc.c -DMAIN

3
gcc-test/src/lib.rs

@ -10,4 +10,7 @@ extern {
#[cfg(windows)]
pub fn windows();
#[cfg(target_env = "msvc")]
pub fn msvc();
}

7
gcc-test/src/msvc.c

@ -0,0 +1,7 @@
#include <windows.h>
void msvc() {}
#ifdef MAIN
int main() {}
#endif

8
gcc-test/tests/all.rs

@ -38,3 +38,11 @@ fn windows_here() {
windows();
}
}
#[test]
#[cfg(target_env = "msvc")]
fn msvc_here() {
unsafe {
msvc();
}
}

41
src/windows_registry.rs

@ -31,8 +31,9 @@ pub fn find(_target: &str, _tool: &str) -> Option<Command> {
pub fn find(target: &str, tool: &str) -> Option<Command> {
use std::env;
use std::ffi::OsString;
use std::io;
use std::fs;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use registry::{RegistryKey, LOCAL_MACHINE};
if !target.contains("msvc") { return None }
@ -121,6 +122,9 @@ pub fn find(target: &str, tool: &str) -> Option<Command> {
let mut includes = Vec::new();
if let Some(ref vs_install_dir) = vs_install_dir {
includes.push(vs_install_dir.join("VC/include"));
if let Some((ucrt_root, vers)) = ucrt_install_dir(vs_install_dir) {
includes.push(ucrt_root.join("Include").join(vers).join("ucrt"));
}
}
if let Some((path, major)) = get_windows_sdk_path() {
if major >= 8 {
@ -141,6 +145,12 @@ pub fn find(target: &str, tool: &str) -> Option<Command> {
let mut libs = Vec::new();
if let Some(ref vs_install_dir) = vs_install_dir {
libs.push(vs_install_dir.join("VC/lib").join(extra));
if let Some((ucrt_root, vers)) = ucrt_install_dir(vs_install_dir) {
if let Some(arch) = windows_sdk_v8_subdir(target) {
libs.push(ucrt_root.join("Lib").join(vers)
.join("ucrt").join(arch));
}
}
}
if let Some(path) = get_windows_sdk_lib_path(target) {
libs.push(path);
@ -294,4 +304,33 @@ pub fn find(target: &str, tool: &str) -> Option<Command> {
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 sdk_dir = match get_windows_sdk_path() {
Some((mut root, _)) => { root.pop(); root.push("10"); root }
None => 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)
}
}

Loading…
Cancel
Save