зеркало из https://github.com/mozilla/sccache.git
Detect MSVC -showIncludes prefix (not actually wired up to anything yet)
This commit is contained in:
Родитель
0f4c6b888e
Коммит
86aa35b191
|
@ -5,6 +5,7 @@ dependencies = [
|
|||
"clap 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -14,6 +15,7 @@ dependencies = [
|
|||
"rusoto 0.13.1 (git+https://github.com/rusoto/rusoto?branch=feature_mutex_credentials)",
|
||||
"sha1 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempdir 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"zip 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@ protobuf = "1.0.18"
|
|||
retry = "0.4.0"
|
||||
sha1 = "0.1.1"
|
||||
tempdir = "0.3.4"
|
||||
winapi = "0.2"
|
||||
kernel32-sys = "0.2.2"
|
||||
zip = { version = "0.1", default-features = false }
|
||||
|
||||
[dependencies.rusoto]
|
||||
|
|
|
@ -22,6 +22,7 @@ use compiler::{
|
|||
gcc,
|
||||
msvc,
|
||||
};
|
||||
use compiler::msvc::maybe_str;
|
||||
use filetime::FileTime;
|
||||
use log::LogLevel::Trace;
|
||||
use mock_command::{
|
||||
|
@ -49,14 +50,17 @@ use std::thread;
|
|||
use tempdir::TempDir;
|
||||
|
||||
/// Supported compilers.
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum CompilerKind {
|
||||
/// GCC
|
||||
Gcc,
|
||||
/// clang
|
||||
Clang,
|
||||
/// Microsoft Visual C++
|
||||
Msvc,
|
||||
Msvc {
|
||||
/// The prefix used in the output of `-showIncludes`.
|
||||
includes_prefix: Vec<u8>,
|
||||
},
|
||||
}
|
||||
|
||||
impl CompilerKind {
|
||||
|
@ -66,7 +70,7 @@ impl CompilerKind {
|
|||
// accept different sets of arguments.
|
||||
&CompilerKind::Gcc => gcc::parse_arguments(arguments, gcc::argument_takes_value),
|
||||
&CompilerKind::Clang => gcc::parse_arguments(arguments, clang::argument_takes_value),
|
||||
&CompilerKind::Msvc => msvc::parse_arguments(arguments),
|
||||
&CompilerKind::Msvc { .. } => msvc::parse_arguments(arguments),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,7 +80,7 @@ impl CompilerKind {
|
|||
// GCC and clang use the same preprocessor invocation.
|
||||
gcc::preprocess(creator, compiler, parsed_args, cwd)
|
||||
},
|
||||
&CompilerKind::Msvc => msvc::preprocess(creator, compiler, parsed_args, cwd),
|
||||
&CompilerKind::Msvc { .. } => msvc::preprocess(creator, compiler, parsed_args, cwd),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,7 +88,7 @@ impl CompilerKind {
|
|||
match self {
|
||||
&CompilerKind::Gcc => gcc::compile(creator, compiler, preprocessor_output, parsed_args, cwd),
|
||||
&CompilerKind::Clang => clang::compile(creator, compiler, preprocessor_output, parsed_args, cwd),
|
||||
&CompilerKind::Msvc => msvc::compile(creator, compiler, preprocessor_output, parsed_args, cwd),
|
||||
&CompilerKind::Msvc { .. } => msvc::compile(creator, compiler, preprocessor_output, parsed_args, cwd),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -332,7 +336,11 @@ gcc
|
|||
return Ok(Some(CompilerKind::Clang));
|
||||
} else if line == "msvc" {
|
||||
trace!("Found MSVC");
|
||||
return Ok(Some(CompilerKind::Msvc));
|
||||
let prefix = try!(msvc::detect_showincludes_prefix(&mut creator, &executable));
|
||||
trace!("showIncludes prefix: '{}'", maybe_str(&prefix));
|
||||
return Ok(Some(CompilerKind::Msvc {
|
||||
includes_prefix: prefix,
|
||||
}));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
|
@ -427,8 +435,19 @@ mod test {
|
|||
#[test]
|
||||
fn test_detect_compiler_kind_msvc() {
|
||||
let creator = new_creator();
|
||||
let f = TestFixture::new();
|
||||
let srcfile = f.touch("stdio.h").unwrap();
|
||||
let mut s = srcfile.to_str().unwrap();
|
||||
if s.starts_with("\\\\?\\") {
|
||||
s = &s[4..];
|
||||
}
|
||||
let prefix = "blah: ";
|
||||
let stdout = format!("{}{}\r\n", prefix, s);
|
||||
// Compiler detection output
|
||||
next_command(&creator, Ok(MockChild::new(exit_status(0), "foo\nmsvc\nbar", "")));
|
||||
assert_eq!(Some(CompilerKind::Msvc), detect_compiler_kind(creator.clone(), "/foo/bar"));
|
||||
// showincludes prefix detection output
|
||||
next_command(&creator, Ok(MockChild::new(exit_status(0), &stdout, &String::new())));
|
||||
assert_eq!(Some(CompilerKind::Msvc { includes_prefix: prefix.as_bytes().iter().map(|&b| b).collect() }), detect_compiler_kind(creator.clone(), "/foo/bar"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -25,7 +25,9 @@ use mock_command::{
|
|||
CommandCreatorSync,
|
||||
RunCommand,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::File;
|
||||
use std::io::{
|
||||
self,
|
||||
|
@ -34,9 +36,76 @@ use std::io::{
|
|||
Write,
|
||||
};
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
use std::process::{self,Stdio};
|
||||
use std::str;
|
||||
use tempdir::TempDir;
|
||||
|
||||
#[cfg(windows)]
|
||||
fn file_exists(filename: &[u8]) -> bool {
|
||||
use kernel32;
|
||||
use std::ffi::CString;
|
||||
use winapi::fileapi::INVALID_FILE_ATTRIBUTES;
|
||||
CString::new(filename).map(|c| {
|
||||
unsafe { kernel32::GetFileAttributesA(c.as_ptr()) != INVALID_FILE_ATTRIBUTES }
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn file_exists(filename: &[u8]) -> bool {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
Path::new(OsStr::from_bytes(filename)).exists()
|
||||
}
|
||||
|
||||
pub fn maybe_str(bytes: &[u8]) -> Cow<str> {
|
||||
str::from_utf8(bytes)
|
||||
.map(|s| Cow::Borrowed(s))
|
||||
.unwrap_or(Cow::Owned(format!("{:?}", bytes)))
|
||||
}
|
||||
|
||||
/// Detect the prefix included in the output of MSVC's -showIncludes output.
|
||||
pub fn detect_showincludes_prefix<T : CommandCreatorSync, U: AsRef<OsStr>>(mut creator: &mut T, exe: U) -> io::Result<Vec<u8>> {
|
||||
let tempdir = try!(TempDir::new("sccache"));
|
||||
let input = tempdir.path().join("test.c");
|
||||
{
|
||||
try!(File::create(&input)
|
||||
.and_then(|mut f| f.write_all(b"#include <stdio.h>\n")))
|
||||
}
|
||||
|
||||
let mut cmd = creator.new_command_sync(&exe);
|
||||
cmd.args(&["-nologo", "-showIncludes", "-c", "-Fonul"])
|
||||
.arg(&input)
|
||||
// The MSDN docs say the -showIncludes output goes to stderr,
|
||||
// but that's just not true.
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::null());
|
||||
|
||||
if log_enabled!(Trace) {
|
||||
trace!("detect_showincludes_prefix: {:?}", cmd);
|
||||
}
|
||||
|
||||
let output = try!(run_input_output(cmd, None));
|
||||
if output.status.success() {
|
||||
let process::Output { stdout, .. } = output;
|
||||
for line in stdout.split(|&b| b == b'\n') {
|
||||
if line.ends_with(b"stdio.h\r") {
|
||||
for (i, c) in line.iter().enumerate().rev() {
|
||||
if *c == b' ' {
|
||||
let len = line.len();
|
||||
// See if the rest of this line is a full pathname.
|
||||
if file_exists(&line[i+1..len-1]) {
|
||||
// Everything from the beginning of the line
|
||||
// to this index is the prefix.
|
||||
return Ok(line[..i+1].iter().map(|&b| b).collect());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Err(Error::new(ErrorKind::Other, "Failed to detect showIncludes prefix"));
|
||||
}
|
||||
|
||||
pub fn parse_arguments(arguments: &[String]) -> CompilerArguments {
|
||||
let mut output_arg = None;
|
||||
let mut input_arg = None;
|
||||
|
@ -219,11 +288,31 @@ pub fn compile<T : CommandCreatorSync>(mut creator: T, compiler: &Compiler, prep
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use env_logger;
|
||||
use std::collections::HashMap;
|
||||
use mock_command::*;
|
||||
use ::compiler::*;
|
||||
use test::utils::*;
|
||||
|
||||
#[test]
|
||||
fn test_detect_showincludes_prefix() {
|
||||
match env_logger::init() {
|
||||
Ok(_) => {},
|
||||
Err(_) => {},
|
||||
}
|
||||
let mut creator = new_creator();
|
||||
let f = TestFixture::new();
|
||||
let srcfile = f.touch("stdio.h").unwrap();
|
||||
let mut s = srcfile.to_str().unwrap();
|
||||
if s.starts_with("\\\\?\\") {
|
||||
s = &s[4..];
|
||||
}
|
||||
let stdout = format!("blah: {}\r\n", s);
|
||||
let stderr = String::from("some\r\nstderr\r\n");
|
||||
next_command(&creator, Ok(MockChild::new(exit_status(0), &stdout, &stderr)));
|
||||
assert_eq!(&b"blah: "[..], AsRef::<[u8]>::as_ref(&detect_showincludes_prefix(&mut creator, "cl.exe").unwrap()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_arguments_simple() {
|
||||
match parse_arguments(&stringvec!["-c", "foo.c", "-Fofoo.obj"]) {
|
||||
|
@ -346,7 +435,7 @@ mod test {
|
|||
common_args: vec!(),
|
||||
};
|
||||
let compiler = Compiler::new(f.bins[0].to_str().unwrap(),
|
||||
CompilerKind::Msvc).unwrap();
|
||||
CompilerKind::Msvc { includes_prefix: vec!() }).unwrap();
|
||||
// Compiler invocation.
|
||||
next_command(&creator, Ok(MockChild::new(exit_status(0), "", "")));
|
||||
let (cacheable, _) = compile(creator.clone(), &compiler, vec!(), &parsed_args, f.tempdir.path().to_str().unwrap()).unwrap();
|
||||
|
@ -369,7 +458,7 @@ mod test {
|
|||
common_args: vec!(),
|
||||
};
|
||||
let compiler = Compiler::new(f.bins[0].to_str().unwrap(),
|
||||
CompilerKind::Msvc).unwrap();
|
||||
CompilerKind::Msvc { includes_prefix: vec!() }).unwrap();
|
||||
// Compiler invocation.
|
||||
next_command(&creator, Ok(MockChild::new(exit_status(0), "", "")));
|
||||
let (cacheable, _) = compile(creator.clone(), &compiler, vec!(), &parsed_args, f.tempdir.path().to_str().unwrap()).unwrap();
|
||||
|
@ -390,7 +479,7 @@ mod test {
|
|||
common_args: vec!(),
|
||||
};
|
||||
let compiler = Compiler::new(f.bins[0].to_str().unwrap(),
|
||||
CompilerKind::Msvc).unwrap();
|
||||
CompilerKind::Msvc { includes_prefix: vec!() }).unwrap();
|
||||
// First compiler invocation fails.
|
||||
next_command(&creator, Ok(MockChild::new(exit_status(1), "", "")));
|
||||
// Second compiler invocation succeeds.
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
extern crate clap;
|
||||
extern crate env_logger;
|
||||
extern crate filetime;
|
||||
extern crate kernel32;
|
||||
#[macro_use] extern crate log;
|
||||
extern crate libc;
|
||||
extern crate mio;
|
||||
|
@ -24,6 +25,7 @@ extern crate retry;
|
|||
extern crate rusoto;
|
||||
extern crate sha1;
|
||||
extern crate tempdir;
|
||||
extern crate winapi;
|
||||
extern crate zip;
|
||||
|
||||
// To get macros in scope, this has to be first.
|
||||
|
|
Загрузка…
Ссылка в новой задаче