From 61a867013e88e061ed85c82b88ae0d50b0141f52 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 23 Jul 2015 10:09:33 -0700 Subject: [PATCH] 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). --- appveyor.yml | 10 +++++++++- gcc-test/build.rs | 38 ++++++++++++++++++++++++++++++++++++++ gcc-test/src/NMakefile | 13 +++++++++++++ gcc-test/src/lib.rs | 3 +++ gcc-test/src/msvc.c | 7 +++++++ gcc-test/tests/all.rs | 8 ++++++++ src/windows_registry.rs | 41 ++++++++++++++++++++++++++++++++++++++++- 7 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 gcc-test/src/NMakefile create mode 100644 gcc-test/src/msvc.c diff --git a/appveyor.yml b/appveyor.yml index 00922c1..82ef66d 100644 --- a/appveyor.yml +++ b/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 diff --git a/gcc-test/build.rs b/gcc-test/build.rs index 566453b..141e36f 100644 --- a/gcc-test/build.rs +++ b/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()); + } } diff --git a/gcc-test/src/NMakefile b/gcc-test/src/NMakefile new file mode 100644 index 0000000..e3fd993 --- /dev/null +++ b/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 diff --git a/gcc-test/src/lib.rs b/gcc-test/src/lib.rs index 7d9ca96..9f07097 100644 --- a/gcc-test/src/lib.rs +++ b/gcc-test/src/lib.rs @@ -10,4 +10,7 @@ extern { #[cfg(windows)] pub fn windows(); + + #[cfg(target_env = "msvc")] + pub fn msvc(); } diff --git a/gcc-test/src/msvc.c b/gcc-test/src/msvc.c new file mode 100644 index 0000000..dbbc494 --- /dev/null +++ b/gcc-test/src/msvc.c @@ -0,0 +1,7 @@ +#include + +void msvc() {} + +#ifdef MAIN +int main() {} +#endif diff --git a/gcc-test/tests/all.rs b/gcc-test/tests/all.rs index 822a2ef..ef58550 100644 --- a/gcc-test/tests/all.rs +++ b/gcc-test/tests/all.rs @@ -38,3 +38,11 @@ fn windows_here() { windows(); } } + +#[test] +#[cfg(target_env = "msvc")] +fn msvc_here() { + unsafe { + msvc(); + } +} diff --git a/src/windows_registry.rs b/src/windows_registry.rs index c4e6c8a..81fcd43 100644 --- a/src/windows_registry.rs +++ b/src/windows_registry.rs @@ -31,8 +31,9 @@ pub fn find(_target: &str, _tool: &str) -> Option { pub fn find(target: &str, tool: &str) -> Option { 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 { 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 { 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 { 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::() { + if Some(u) > max { + max = Some(u); + max_s = Some(s); + } + } + } + } + Ok(max_s.map(|m| (sdk_dir, m))) + })().ok().and_then(|x| x) + } }