diff options
author | Daniel Mueller <deso@posteo.net> | 2019-05-24 18:08:42 -0700 |
---|---|---|
committer | Daniel Mueller <deso@posteo.net> | 2019-05-24 18:08:42 -0700 |
commit | b637d5284c6117da3bfeb471da7c62e53a632621 (patch) | |
tree | b96df01ed2c0f14a02a6ec62de7d834c153435f0 /cc/src | |
parent | 82cf43dd887801b8b22b8aae8c02854d921915d5 (diff) | |
download | nitrocli-b637d5284c6117da3bfeb471da7c62e53a632621.tar.gz nitrocli-b637d5284c6117da3bfeb471da7c62e53a632621.tar.bz2 |
Update cc crate to 1.0.37
This change updates the cc crate to version 1.0.37.
Import subrepo cc/:cc at cbf6d2f1312b6be22a7a363cf5c2a02acabc531f
Diffstat (limited to 'cc/src')
-rw-r--r-- | cc/src/com.rs | 4 | ||||
-rw-r--r-- | cc/src/lib.rs | 293 | ||||
-rw-r--r-- | cc/src/setup_config.rs | 22 | ||||
-rw-r--r-- | cc/src/winapi.rs | 4 | ||||
-rw-r--r-- | cc/src/windows_registry.rs | 112 |
5 files changed, 288 insertions, 147 deletions
diff --git a/cc/src/com.rs b/cc/src/com.rs index 2b16475..9b75d47 100644 --- a/cc/src/com.rs +++ b/cc/src/com.rs @@ -13,12 +13,12 @@ use std::ops::Deref; use std::os::windows::ffi::{OsStrExt, OsStringExt}; use std::ptr::null_mut; use std::slice::from_raw_parts; +use winapi::CoInitializeEx; +use winapi::IUnknown; use winapi::Interface; use winapi::BSTR; -use winapi::CoInitializeEx; use winapi::COINIT_MULTITHREADED; use winapi::{SysFreeString, SysStringLen}; -use winapi::IUnknown; use winapi::{HRESULT, S_FALSE, S_OK}; pub fn initialize() -> Result<(), HRESULT> { diff --git a/cc/src/lib.rs b/cc/src/lib.rs index 5eebd07..9fef147 100644 --- a/cc/src/lib.rs +++ b/cc/src/lib.rs @@ -61,15 +61,15 @@ #[cfg(feature = "parallel")] extern crate rayon; +use std::collections::HashMap; use std::env; use std::ffi::{OsStr, OsString}; use std::fs; +use std::io::{self, BufRead, BufReader, Read, Write}; use std::path::{Path, PathBuf}; use std::process::{Child, Command, Stdio}; -use std::io::{self, BufRead, BufReader, Read, Write}; -use std::thread::{self, JoinHandle}; -use std::collections::HashMap; use std::sync::{Arc, Mutex}; +use std::thread::{self, JoinHandle}; // These modules are all glue to support reading the MSVC version from // the registry and from COM interfaces @@ -891,7 +891,7 @@ impl Build { return Err(Error::new( ErrorKind::IOError, "Getting object file details failed.", - )) + )); } }; @@ -956,7 +956,7 @@ impl Build { fn compile_objects(&self, objs: &[Object]) -> Result<(), Error> { use self::rayon::prelude::*; - if let Ok(amt) = env::var("NUM_JOBS") { + if let Some(amt) = self.getenv("NUM_JOBS") { if let Ok(amt) = amt.parse() { let _ = rayon::ThreadPoolBuilder::new() .num_threads(amt) @@ -1093,7 +1093,86 @@ impl Build { let target = self.get_target()?; let mut cmd = self.get_base_compiler()?; + let envflags = self.envflags(if self.cpp { "CXXFLAGS" } else { "CFLAGS" }); + + // Disable default flag generation via environment variable or when + // certain cross compiling arguments are set + let use_defaults = self.getenv("CRATE_CC_NO_DEFAULTS").is_none(); + + if use_defaults { + self.add_default_flags(&mut cmd, &target, &opt_level)?; + } else { + println!("Info: default compiler flags are disabled"); + } + + for arg in envflags { + cmd.push_cc_arg(arg.into()); + } + + for directory in self.include_directories.iter() { + cmd.args.push(cmd.family.include_flag().into()); + cmd.args.push(directory.into()); + } + + // If warnings and/or extra_warnings haven't been explicitly set, + // then we set them only if the environment doesn't already have + // CFLAGS/CXXFLAGS, since those variables presumably already contain + // the desired set of warnings flags. + + if self + .warnings + .unwrap_or(if self.has_flags() { false } else { true }) + { + let wflags = cmd.family.warnings_flags().into(); + cmd.push_cc_arg(wflags); + } + + if self + .extra_warnings + .unwrap_or(if self.has_flags() { false } else { true }) + { + if let Some(wflags) = cmd.family.extra_warnings_flags() { + cmd.push_cc_arg(wflags.into()); + } + } + + for flag in self.flags.iter() { + cmd.args.push(flag.into()); + } + for flag in self.flags_supported.iter() { + if self.is_flag_supported(flag).unwrap_or(false) { + cmd.push_cc_arg(flag.into()); + } + } + + for &(ref key, ref value) in self.definitions.iter() { + let lead = if let ToolFamily::Msvc { .. } = cmd.family { + "/" + } else { + "-" + }; + if let Some(ref value) = *value { + cmd.args.push(format!("{}D{}={}", lead, key, value).into()); + } else { + cmd.args.push(format!("{}D{}", lead, key).into()); + } + } + + if self.warnings_into_errors { + let warnings_to_errors_flag = cmd.family.warnings_to_errors_flag().into(); + cmd.push_cc_arg(warnings_to_errors_flag); + } + + Ok(cmd) + } + + fn add_default_flags( + &self, + cmd: &mut Tool, + target: &str, + opt_level: &str, + ) -> Result<(), Error> { // Non-target flags // If the flag is not conditioned on target variable, it belongs here :) match cmd.family { @@ -1107,8 +1186,9 @@ impl Build { Some(true) => "/MT", Some(false) => "/MD", None => { - let features = - env::var("CARGO_CFG_TARGET_FEATURE").unwrap_or(String::new()); + let features = self + .getenv("CARGO_CFG_TARGET_FEATURE") + .unwrap_or(String::new()); if features.contains("crt-static") { "/MT" } else { @@ -1120,9 +1200,9 @@ impl Build { match &opt_level[..] { // Msvc uses /O1 to enable all optimizations that minimize code size. - "z" | "s" | "1" => cmd.args.push("/O1".into()), + "z" | "s" | "1" => cmd.push_opt_unless_duplicate("/O1".into()), // -O3 is a valid value for gcc and clang compilers, but not msvc. Cap to /O2. - "2" | "3" => cmd.args.push("/O2".into()), + "2" | "3" => cmd.push_opt_unless_duplicate("/O2".into()), _ => {} } } @@ -1130,9 +1210,9 @@ impl Build { // arm-linux-androideabi-gcc 4.8 shipped with Android NDK does // not support '-Oz' if opt_level == "z" && cmd.family != ToolFamily::Clang { - cmd.args.push("-Os".into()); + cmd.push_opt_unless_duplicate("-Os".into()); } else { - cmd.args.push(format!("-O{}", opt_level).into()); + cmd.push_opt_unless_duplicate(format!("-O{}", opt_level).into()); } if !target.contains("-ios") { @@ -1149,9 +1229,6 @@ impl Build { } } } - for arg in self.envflags(if self.cpp { "CXXFLAGS" } else { "CFLAGS" }) { - cmd.args.push(arg.into()); - } if self.get_debug() { if self.cuda { @@ -1159,7 +1236,7 @@ impl Build { cmd.args.push(nvcc_debug_flag); } let family = cmd.family; - family.add_debug_flags(&mut cmd); + family.add_debug_flags(cmd); } // Target flags @@ -1171,11 +1248,11 @@ impl Build { if clang_cl { if target.contains("x86_64") { cmd.args.push("-m64".into()); - } else if target.contains("i586") { + } else if target.contains("86") { cmd.args.push("-m32".into()); cmd.args.push("/arch:IA32".into()); } else { - cmd.args.push("-m32".into()); + cmd.args.push(format!("--target={}", target).into()); } } else { if target.contains("i586") { @@ -1193,7 +1270,8 @@ impl Build { // the SDK, but for all released versions of the // Windows SDK it is required. if target.contains("arm") || target.contains("thumb") { - cmd.args.push("/D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1".into()); + cmd.args + .push("/D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1".into()); } } ToolFamily::Gnu => { @@ -1206,14 +1284,18 @@ impl Build { } if self.static_flag.is_none() { - let features = env::var("CARGO_CFG_TARGET_FEATURE").unwrap_or(String::new()); + let features = self + .getenv("CARGO_CFG_TARGET_FEATURE") + .unwrap_or(String::new()); if features.contains("crt-static") { cmd.args.push("-static".into()); } } // armv7 targets get to use armv7 instructions - if (target.starts_with("armv7") || target.starts_with("thumbv7")) && target.contains("-linux-") { + if (target.starts_with("armv7") || target.starts_with("thumbv7")) + && target.contains("-linux-") + { cmd.args.push("-march=armv7-a".into()); } @@ -1346,7 +1428,7 @@ impl Build { if target.contains("-ios") { // FIXME: potential bug. iOS is always compiled with Clang, but Gcc compiler may be // detected instead. - self.ios_flags(&mut cmd)?; + self.ios_flags(cmd)?; } if self.static_flag.unwrap_or(false) { @@ -1372,62 +1454,17 @@ impl Build { } } - for directory in self.include_directories.iter() { - cmd.args.push(cmd.family.include_flag().into()); - cmd.args.push(directory.into()); - } - - // If warnings and/or extra_warnings haven't been explicitly set, - // then we set them only if the environment doesn't already have - // CFLAGS/CXXFLAGS, since those variables presumably already contain - // the desired set of warnings flags. - - if self.warnings.unwrap_or(if self.has_flags() { false } else { true }) { - let wflags = cmd.family.warnings_flags().into(); - cmd.push_cc_arg(wflags); - } - - if self.extra_warnings.unwrap_or(if self.has_flags() { false } else { true }) { - if let Some(wflags) = cmd.family.extra_warnings_flags() { - cmd.push_cc_arg(wflags.into()); - } - } - - for flag in self.flags.iter() { - cmd.args.push(flag.into()); - } - - for flag in self.flags_supported.iter() { - if self.is_flag_supported(flag).unwrap_or(false) { - cmd.push_cc_arg(flag.into()); - } - } - - for &(ref key, ref value) in self.definitions.iter() { - let lead = if let ToolFamily::Msvc { .. } = cmd.family { - "/" - } else { - "-" - }; - if let Some(ref value) = *value { - cmd.args.push(format!("{}D{}={}", lead, key, value).into()); - } else { - cmd.args.push(format!("{}D{}", lead, key).into()); - } - } - - if self.warnings_into_errors { - let warnings_to_errors_flag = cmd.family.warnings_to_errors_flag().into(); - cmd.push_cc_arg(warnings_to_errors_flag); - } - - Ok(cmd) + Ok(()) } fn has_flags(&self) -> bool { let flags_env_var_name = if self.cpp { "CXXFLAGS" } else { "CFLAGS" }; let flags_env_var_value = self.get_var(flags_env_var_name); - if let Ok(_) = flags_env_var_value { true } else { false } + if let Ok(_) = flags_env_var_value { + true + } else { + false + } } fn msvc_macro_assembler(&self) -> Result<(Command, String), Error> { @@ -1471,12 +1508,7 @@ impl Build { let objects: Vec<_> = objs.iter().map(|obj| obj.dst.clone()).collect(); let target = self.get_target()?; if target.contains("msvc") { - let mut cmd = match self.archiver { - Some(ref s) => self.cmd(s), - None => windows_registry::find(&target, "lib.exe") - .unwrap_or_else(|| self.cmd("lib.exe")), - }; - + let (mut cmd, program) = self.get_ar()?; let mut out = OsString::from("/OUT:"); out.push(dst); cmd.arg(out).arg("/nologo"); @@ -1521,7 +1553,7 @@ impl Build { } else { cmd.args(&objects).args(&self.objects); } - run(&mut cmd, "lib.exe")?; + run(&mut cmd, &program)?; // The Rust compiler will look for libfoo.a and foo.lib, but the // MSVC linker will also be passed foo.lib, so be sure that both @@ -1537,7 +1569,7 @@ impl Build { return Err(Error::new( ErrorKind::IOError, "Could not copy or create a hard-link to the generated lib file.", - )) + )); } }; } else { @@ -1574,7 +1606,7 @@ impl Build { return Err(Error::new( ErrorKind::ArchitectureInvalid, "Unknown architecture for iOS target.", - )) + )); } }; @@ -1593,7 +1625,8 @@ impl Build { }; self.print(&format!("Detecting iOS SDK path for {}", sdk)); - let sdk_path = self.cmd("xcrun") + let sdk_path = self + .cmd("xcrun") .arg("--show-sdk-path") .arg("--sdk") .arg(sdk) @@ -1607,7 +1640,7 @@ impl Build { return Err(Error::new( ErrorKind::IOError, "Unable to determine iOS SDK path.", - )) + )); } }; @@ -1658,7 +1691,8 @@ impl Build { let cl_exe = windows_registry::find_tool(&target, "cl.exe"); - let tool_opt: Option<Tool> = self.env_tool(env) + let tool_opt: Option<Tool> = self + .env_tool(env) .map(|(tool, cc, args)| { // chop off leading/trailing whitespace to work around // semi-buggy build scripts which are shared in @@ -1717,6 +1751,10 @@ impl Build { } } else if target.contains("cloudabi") { format!("{}-{}", target, traditional) + } else if target == "wasm32-wasi" || + target == "wasm32-unknown-wasi" || + target == "wasm32-unknown-unknown" { + "clang".to_string() } else if self.get_host()? != target { // CROSS_COMPILE is of the form: "arm-linux-gnueabi-" let cc_env = self.getenv("CROSS_COMPILE"); @@ -1751,6 +1789,12 @@ impl Build { "mipsel-unknown-linux-gnu" => Some("mipsel-linux-gnu"), "mips64-unknown-linux-gnuabi64" => Some("mips64-linux-gnuabi64"), "mips64el-unknown-linux-gnuabi64" => Some("mips64el-linux-gnuabi64"), + "mipsisa32r6-unknown-linux-gnu" => Some("mipsisa32r6-linux-gnu"), + "mipsisa32r6el-unknown-linux-gnu" => Some("mipsisa32r6el-linux-gnu"), + "mipsisa64r6-unknown-linux-gnuabi64" => Some("mipsisa64r6-linux-gnuabi64"), + "mipsisa64r6el-unknown-linux-gnuabi64" => { + Some("mipsisa64r6el-linux-gnuabi64") + } "powerpc-unknown-linux-gnu" => Some("powerpc-linux-gnu"), "powerpc-unknown-linux-gnuspe" => Some("powerpc-linux-gnuspe"), "powerpc-unknown-netbsd" => Some("powerpc--netbsd"), @@ -1818,9 +1862,9 @@ impl Build { // configure for invocations like `clang-cl` we still get a "works out // of the box" experience. if let Some(cl_exe) = cl_exe { - if tool.family == (ToolFamily::Msvc { clang_cl: true }) && - tool.env.len() == 0 && - target.contains("msvc") + if tool.family == (ToolFamily::Msvc { clang_cl: true }) + && tool.env.len() == 0 + && target.contains("msvc") { for &(ref k, ref v) in cl_exe.env.iter() { tool.env.push((k.to_owned(), v.to_owned())); @@ -1836,7 +1880,8 @@ impl Build { let host = self.get_host()?; let kind = if host == target { "HOST" } else { "TARGET" }; let target_u = target.replace("-", "_"); - let res = self.getenv(&format!("{}_{}", var_base, target)) + let res = self + .getenv(&format!("{}_{}", var_base, target)) .or_else(|| self.getenv(&format!("{}_{}", var_base, target_u))) .or_else(|| self.getenv(&format!("{}_{}", kind, var_base))) .or_else(|| self.getenv(var_base)); @@ -1961,9 +2006,10 @@ impl Build { if let Ok(p) = self.get_var("AR") { return Ok((self.cmd(&p), p)); } - let program = if self.get_target()?.contains("android") { - format!("{}-ar", self.get_target()?.replace("armv7", "arm")) - } else if self.get_target()?.contains("emscripten") { + let target = self.get_target()?; + let program = if target.contains("android") { + format!("{}-ar", target.replace("armv7", "arm")) + } else if target.contains("emscripten") { // Windows use bat files so we have to be a bit more specific if cfg!(windows) { let mut cmd = self.cmd("cmd"); @@ -1972,6 +2018,11 @@ impl Build { } "emar".to_string() + } else if target.contains("msvc") { + match windows_registry::find(&target, "lib.exe") { + Some(t) => return Ok((t, "lib.exe".to_string())), + None => "lib.exe".to_string(), + } } else { "ar".to_string() }; @@ -2021,7 +2072,7 @@ impl Build { fn getenv(&self, v: &str) -> Option<String> { let mut cache = self.env_cache.lock().unwrap(); if let Some(val) = cache.get(v) { - return val.clone() + return val.clone(); } let r = env::var(v).ok(); self.print(&format!("{} = {:?}", v, r)); @@ -2062,10 +2113,11 @@ impl Tool { let family = if let Some(fname) = path.file_name().and_then(|p| p.to_str()) { if fname.contains("clang-cl") { ToolFamily::Msvc { clang_cl: true } - } else if fname.contains("cl") && - !fname.contains("cloudabi") && - !fname.contains("uclibc") && - !fname.contains("clang") { + } else if fname.contains("cl") + && !fname.contains("cloudabi") + && !fname.contains("uclibc") + && !fname.contains("clang") + { ToolFamily::Msvc { clang_cl: false } } else if fname.contains("clang") { ToolFamily::Clang @@ -2104,6 +2156,42 @@ impl Tool { self.args.push(flag); } + fn is_duplicate_opt_arg(&self, flag: &OsString) -> bool { + let flag = flag.to_str().unwrap(); + let mut chars = flag.chars(); + + // Only duplicate check compiler flags + if self.is_like_msvc() { + if chars.next() != Some('/') { + return false; + } + } else if self.is_like_gnu() || self.is_like_clang() { + if chars.next() != Some('-') { + return false; + } + } + + // Check for existing optimization flags (-O, /O) + if chars.next() == Some('O') { + return self + .args() + .iter() + .any(|ref a| a.to_str().unwrap_or("").chars().nth(1) == Some('O')); + } + + // TODO Check for existing -m..., -m...=..., /arch:... flags + return false; + } + + /// Don't push optimization arg if it conflicts with existing args + fn push_opt_unless_duplicate(&mut self, flag: OsString) { + if self.is_duplicate_opt_arg(&flag) { + println!("Info: Ignoring duplicate arg {:?}", &flag); + } else { + self.push_cc_arg(flag); + } + } + /// Converts this compiler into a `Command` that's ready to be run. /// /// This is useful for when the compiler needs to be executed and the @@ -2120,7 +2208,11 @@ impl Tool { }; cmd.args(&self.cc_wrapper_args); - let value = self.args.iter().filter(|a| !self.removed_args.contains(a)).collect::<Vec<_>>(); + let value = self + .args + .iter() + .filter(|a| !self.removed_args.contains(a)) + .collect::<Vec<_>>(); cmd.args(&value); for &(ref k, ref v) in self.env.iter() { @@ -2215,7 +2307,7 @@ fn run(cmd: &mut Command, program: &str) -> Result<(), Error> { "Failed to wait on spawned child process, command {:?} with args {:?}.", cmd, program ), - )) + )); } }; print.join().unwrap(); @@ -2253,7 +2345,7 @@ fn run_output(cmd: &mut Command, program: &str) -> Result<Vec<u8>, Error> { "Failed to wait on spawned child process, command {:?} with args {:?}.", cmd, program ), - )) + )); } }; print.join().unwrap(); @@ -2311,7 +2403,8 @@ fn spawn(cmd: &mut Command, program: &str) -> Result<(Child, JoinHandle<()>), Er } fn fail(s: &str) -> ! { - panic!("\n\nInternal error occurred: {}\n\n", s) + let _ = writeln!(io::stderr(), "\n\nerror occurred: {}\n\n", s); + std::process::exit(1); } fn command_add_output_file(cmd: &mut Command, dst: &Path, msvc: bool, is_asm: bool, is_arm: bool) { diff --git a/cc/src/setup_config.rs b/cc/src/setup_config.rs index 7c03d38..56fe114 100644 --- a/cc/src/setup_config.rs +++ b/cc/src/setup_config.rs @@ -11,14 +11,14 @@ use std::ffi::OsString; use std::ptr::null_mut; use winapi::Interface; -use winapi::{LPFILETIME, ULONG}; -use winapi::S_FALSE; use winapi::BSTR; use winapi::LPCOLESTR; -use winapi::{CoCreateInstance, CLSCTX_ALL}; use winapi::LPSAFEARRAY; +use winapi::S_FALSE; +use winapi::{CoCreateInstance, CLSCTX_ALL}; use winapi::{IUnknown, IUnknownVtbl}; use winapi::{HRESULT, LCID, LPCWSTR, PULONGLONG}; +use winapi::{LPFILETIME, ULONG}; use com::{BStr, ComPtr}; @@ -31,7 +31,7 @@ pub const eRegistered: InstanceState = 2; pub const eNoRebootRequired: InstanceState = 4; pub const eComplete: InstanceState = -1i32 as u32; -RIDL!{#[uuid(0xb41463c3, 0x8866, 0x43b5, 0xbc, 0x33, 0x2b, 0x06, 0x76, 0xf7, 0xf4, 0x2e)] +RIDL! {#[uuid(0xb41463c3, 0x8866, 0x43b5, 0xbc, 0x33, 0x2b, 0x06, 0x76, 0xf7, 0xf4, 0x2e)] interface ISetupInstance(ISetupInstanceVtbl): IUnknown(IUnknownVtbl) { fn GetInstanceId( pbstrInstanceId: *mut BSTR, @@ -62,7 +62,7 @@ interface ISetupInstance(ISetupInstanceVtbl): IUnknown(IUnknownVtbl) { ) -> HRESULT, }} -RIDL!{#[uuid(0x89143c9a, 0x05af, 0x49b0, 0xb7, 0x17, 0x72, 0xe2, 0x18, 0xa2, 0x18, 0x5c)] +RIDL! {#[uuid(0x89143c9a, 0x05af, 0x49b0, 0xb7, 0x17, 0x72, 0xe2, 0x18, 0xa2, 0x18, 0x5c)] interface ISetupInstance2(ISetupInstance2Vtbl): ISetupInstance(ISetupInstanceVtbl) { fn GetState( pState: *mut InstanceState, @@ -78,7 +78,7 @@ interface ISetupInstance2(ISetupInstance2Vtbl): ISetupInstance(ISetupInstanceVtb ) -> HRESULT, }} -RIDL!{#[uuid(0x6380bcff, 0x41d3, 0x4b2e, 0x8b, 0x2e, 0xbf, 0x8a, 0x68, 0x10, 0xc8, 0x48)] +RIDL! {#[uuid(0x6380bcff, 0x41d3, 0x4b2e, 0x8b, 0x2e, 0xbf, 0x8a, 0x68, 0x10, 0xc8, 0x48)] interface IEnumSetupInstances(IEnumSetupInstancesVtbl): IUnknown(IUnknownVtbl) { fn Next( celt: ULONG, @@ -94,7 +94,7 @@ interface IEnumSetupInstances(IEnumSetupInstancesVtbl): IUnknown(IUnknownVtbl) { ) -> HRESULT, }} -RIDL!{#[uuid(0x42843719, 0xdb4c, 0x46c2, 0x8e, 0x7c, 0x64, 0xf1, 0x81, 0x6e, 0xfd, 0x5b)] +RIDL! {#[uuid(0x42843719, 0xdb4c, 0x46c2, 0x8e, 0x7c, 0x64, 0xf1, 0x81, 0x6e, 0xfd, 0x5b)] interface ISetupConfiguration(ISetupConfigurationVtbl): IUnknown(IUnknownVtbl) { fn EnumInstances( ppEnumInstances: *mut *mut IEnumSetupInstances, @@ -108,7 +108,7 @@ interface ISetupConfiguration(ISetupConfigurationVtbl): IUnknown(IUnknownVtbl) { ) -> HRESULT, }} -RIDL!{#[uuid(0x26aab78c, 0x4a60, 0x49d6, 0xaf, 0x3b, 0x3c, 0x35, 0xbc, 0x93, 0x36, 0x5d)] +RIDL! {#[uuid(0x26aab78c, 0x4a60, 0x49d6, 0xaf, 0x3b, 0x3c, 0x35, 0xbc, 0x93, 0x36, 0x5d)] interface ISetupConfiguration2(ISetupConfiguration2Vtbl): ISetupConfiguration(ISetupConfigurationVtbl) { fn EnumAllInstances( @@ -116,7 +116,7 @@ interface ISetupConfiguration2(ISetupConfiguration2Vtbl): ) -> HRESULT, }} -RIDL!{#[uuid(0xda8d8a16, 0xb2b6, 0x4487, 0xa2, 0xf1, 0x59, 0x4c, 0xcc, 0xcd, 0x6b, 0xf5)] +RIDL! {#[uuid(0xda8d8a16, 0xb2b6, 0x4487, 0xa2, 0xf1, 0x59, 0x4c, 0xcc, 0xcd, 0x6b, 0xf5)] interface ISetupPackageReference(ISetupPackageReferenceVtbl): IUnknown(IUnknownVtbl) { fn GetId( pbstrId: *mut BSTR, @@ -141,7 +141,7 @@ interface ISetupPackageReference(ISetupPackageReferenceVtbl): IUnknown(IUnknownV ) -> HRESULT, }} -RIDL!{#[uuid(0x42b21b78, 0x6192, 0x463e, 0x87, 0xbf, 0xd5, 0x77, 0x83, 0x8f, 0x1d, 0x5c)] +RIDL! {#[uuid(0x42b21b78, 0x6192, 0x463e, 0x87, 0xbf, 0xd5, 0x77, 0x83, 0x8f, 0x1d, 0x5c)] interface ISetupHelper(ISetupHelperVtbl): IUnknown(IUnknownVtbl) { fn ParseVersion( pwszVersion: LPCOLESTR, @@ -154,7 +154,7 @@ interface ISetupHelper(ISetupHelperVtbl): IUnknown(IUnknownVtbl) { ) -> HRESULT, }} -DEFINE_GUID!{CLSID_SetupConfiguration, +DEFINE_GUID! {CLSID_SetupConfiguration, 0x177f0c4a, 0x1cd3, 0x4de7, 0xa3, 0x2c, 0x71, 0xdb, 0xbb, 0x9f, 0xa3, 0x6d} // Safe wrapper around the COM interfaces diff --git a/cc/src/winapi.rs b/cc/src/winapi.rs index cc83963..c416325 100644 --- a/cc/src/winapi.rs +++ b/cc/src/winapi.rs @@ -115,7 +115,7 @@ macro_rules! DEFINE_GUID { Data3: $w2, Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8], }; - } + }; } macro_rules! RIDL { @@ -207,7 +207,7 @@ macro_rules! RIDL { ); } -RIDL!{#[uuid(0x00000000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +RIDL! {#[uuid(0x00000000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] interface IUnknown(IUnknownVtbl) { fn QueryInterface( riid: REFIID, diff --git a/cc/src/windows_registry.rs b/cc/src/windows_registry.rs index ca6b989..af812a7 100644 --- a/cc/src/windows_registry.rs +++ b/cc/src/windows_registry.rs @@ -17,10 +17,12 @@ use Tool; #[cfg(windows)] macro_rules! otry { - ($expr:expr) => (match $expr { - Some(val) => val, - None => return None, - }) + ($expr:expr) => { + match $expr { + Some(val) => val, + None => return None, + } + }; } /// Attempts to find a tool within an MSVC installation using the Windows @@ -103,6 +105,8 @@ pub enum VsVers { Vs14, /// Visual Studio 15 (2017) Vs15, + /// Visual Studio 16 (2019) + Vs16, /// Hidden variant that should not be matched on. Callers that want to /// handle an enumeration of `VsVers` instances should always have a default @@ -128,6 +132,7 @@ pub fn find_vs_version() -> Result<VsVers, String> { match env::var("VisualStudioVersion") { Ok(version) => match &version[..] { + "16.0" => Ok(VsVers::Vs16), "15.0" => Ok(VsVers::Vs15), "14.0" => Ok(VsVers::Vs14), "12.0" => Ok(VsVers::Vs12), @@ -144,7 +149,9 @@ pub fn find_vs_version() -> Result<VsVers, String> { _ => { // Check for the presense of a specific registry key // that indicates visual studio is installed. - if impl_::has_msbuild_version("15.0") { + if impl_::has_msbuild_version("16.0") { + Ok(VsVers::Vs16) + } else if impl_::has_msbuild_version("15.0") { Ok(VsVers::Vs15) } else if impl_::has_msbuild_version("14.0") { Ok(VsVers::Vs14) @@ -166,15 +173,16 @@ pub fn find_vs_version() -> Result<VsVers, String> { #[cfg(windows)] mod impl_ { + use com; + use registry::{RegistryKey, LOCAL_MACHINE}; + use setup_config::{EnumSetupInstances, SetupConfiguration, SetupInstance}; use std::env; use std::ffi::OsString; - use std::mem; - use std::path::{Path, PathBuf}; use std::fs::File; use std::io::Read; - use registry::{RegistryKey, LOCAL_MACHINE}; - use com; - use setup_config::{EnumSetupInstances, SetupConfiguration, SetupInstance}; + use std::mem; + use std::iter; + use std::path::{Path, PathBuf}; use Tool; @@ -210,6 +218,41 @@ mod impl_ { } } + fn vs16_instances() -> Box<Iterator<Item=PathBuf>> { + let instances = if let Some(instances) = vs15_instances() { + instances + } else { + return Box::new(iter::empty()); + }; + Box::new(instances.filter_map(|instance| { + let instance = otry!(instance.ok()); + let installation_name = otry!(instance.installation_name().ok()); + if otry!(installation_name.to_str()).starts_with("VisualStudio/16.") { + Some(PathBuf::from(otry!(instance.installation_path().ok()))) + } else { + None + } + })) + } + + fn find_tool_in_vs16_path(tool: &str, target: &str) -> Option<Tool> { + vs16_instances().filter_map(|path| { + let path = path.join(tool); + if !path.is_file() { + return None; + } + let mut tool = Tool::new(path); + if target.contains("x86_64") { + tool.env.push(("Platform".into(), "X64".into())); + } + Some(tool) + }).next() + } + + fn find_msbuild_vs16(target: &str) -> Option<Tool> { + find_tool_in_vs16_path(r"MSBuild\Current\Bin\MSBuild.exe", target) + } + // In MSVC 15 (2017) MS once again changed the scheme for locating // the tooling. Now we must go through some COM interfaces, which // is super fun for Rust. @@ -251,7 +294,8 @@ mod impl_ { instance .ok() .and_then(|instance| instance.installation_path().ok()) - }).map(|path| PathBuf::from(path).join(tool)) + }) + .map(|path| PathBuf::from(path).join(tool)) .find(|ref path| path.is_file()), None => None, }; @@ -263,7 +307,7 @@ mod impl_ { .ok() .and_then(|key| key.query_str("15.0").ok()) .map(|path| PathBuf::from(path).join(tool)) - .filter(|ref path| path.is_file()); + .and_then(|path| if path.is_file() { Some(path) } else { None }); } path.map(|path| { @@ -319,13 +363,15 @@ mod impl_ { let path = instance_path.join(r"VC\Tools\MSVC").join(version); // This is the path to the toolchain for a particular target, running // on a given host - let bin_path = path.join("bin") + let bin_path = path + .join("bin") .join(&format!("Host{}", host)) .join(&target); // But! we also need PATH to contain the target directory for the host // architecture, because it contains dlls like mspdb140.dll compiled for // the host architecture. - let host_dylib_path = path.join("bin") + let host_dylib_path = path + .join("bin") .join(&format!("Host{}", host)) .join(&host.to_lowercase()); let lib_path = path.join("lib").join(&target); @@ -478,17 +524,16 @@ mod impl_ { let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok()); let root = otry!(key.query_str("KitsRoot10").ok()); let readdir = otry!(Path::new(&root).join("lib").read_dir().ok()); - let max_libdir = otry!( - readdir - .filter_map(|dir| dir.ok()) - .map(|dir| dir.path()) - .filter(|dir| dir.components() - .last() - .and_then(|c| c.as_os_str().to_str()) - .map(|c| c.starts_with("10.") && dir.join("ucrt").is_dir()) - .unwrap_or(false)) - .max() - ); + let max_libdir = otry!(readdir + .filter_map(|dir| dir.ok()) + .map(|dir| dir.path()) + .filter(|dir| dir + .components() + .last() + .and_then(|c| c.as_os_str().to_str()) + .map(|c| c.starts_with("10.") && dir.join("ucrt").is_dir()) + .unwrap_or(false)) + .max()); let version = max_libdir.components().last().unwrap(); let version = version.as_os_str().to_str().unwrap().to_string(); Some((root.into(), version)) @@ -512,12 +557,11 @@ mod impl_ { .map(|dir| dir.path()) .collect::<Vec<_>>(); dirs.sort(); - let dir = otry!( - dirs.into_iter() - .rev() - .filter(|dir| dir.join("um").join("x64").join("kernel32.lib").is_file()) - .next() - ); + let dir = otry!(dirs + .into_iter() + .rev() + .filter(|dir| dir.join("um").join("x64").join("kernel32.lib").is_file()) + .next()); let version = dir.components().last().unwrap(); let version = version.as_os_str().to_str().unwrap().to_string(); Some((root.into(), version)) @@ -637,7 +681,7 @@ mod impl_ { for subkey in key.iter().filter_map(|k| k.ok()) { let val = subkey .to_str() - .and_then(|s| s.trim_start_matches("v").replace(".", "").parse().ok()); + .and_then(|s| s.trim_left_matches("v").replace(".", "").parse().ok()); let val = match val { Some(s) => s, None => continue, @@ -654,6 +698,10 @@ mod impl_ { pub fn has_msbuild_version(version: &str) -> bool { match version { + "16.0" => { + find_msbuild_vs16("x86_64-pc-windows-msvc").is_some() + || find_msbuild_vs16("i686-pc-windows-msvc").is_some() + } "15.0" => { find_msbuild_vs15("x86_64-pc-windows-msvc").is_some() || find_msbuild_vs15("i686-pc-windows-msvc").is_some() |