Browse Source

Add an `Object` representation.

cl-test
Peter Jin 7 years ago
parent
commit
1f96098a96
  1. 83
      src/lib.rs

83
src/lib.rs

@ -240,6 +240,58 @@ impl ToolFamily {
}
}
/// Represents different C-like dialects.
///
/// Each dialect may require different compilers and compiler invocations.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Dialect {
/// Language dialect is C.
C,
/// Language dialect is C++.
Cpp,
/// Language dialect is CUDA C++ (currently a superset of C++11).
Cuda,
}
/// Detect the language dialect based on source file extension.
pub fn autodetect_ext(src: &Path) -> Dialect {
if let Some(ext) = src.extension().and_then(|e| e.to_str()) {
match ext {
"c" => Dialect::C,
"cc" |
"cpp" |
"cxx" => Dialect::Cpp,
"cu" => Dialect::Cuda,
_ => panic!("unknown source extension: {:?}", src),
}
} else {
panic!("source is missing an extension: {:?}", src);
}
}
/// Represents an object.
///
/// This is a source file -> object file pair, with an associated language
/// dialect.
#[derive(Clone, Debug)]
pub struct Object {
dialect: Dialect,
src: PathBuf,
dst: PathBuf,
}
impl Object {
/// Create a new source file -> object file pair, while autodetecting the
/// dialect from the source file extension.
pub fn new(src: PathBuf, dst: PathBuf) -> Object {
Object {
dialect: autodetect_ext(&src),
src: src,
dst: dst,
}
}
}
/// Compile a library from the given set of input C files.
///
/// This will simply compile all files into object files and then assemble them
@ -758,7 +810,6 @@ impl Build {
let dst = self.get_out_dir()?;
let mut objects = Vec::new();
let mut src_dst = Vec::new();
for file in self.files.iter() {
let obj = dst.join(file).with_extension("o");
let obj = if !obj.starts_with(&dst) {
@ -772,10 +823,9 @@ impl Build {
None => return Err(Error::new(ErrorKind::IOError, "Getting object file details failed.")),
};
src_dst.push((file.to_path_buf(), obj.clone()));
objects.push(obj);
objects.push(Object::new(file.to_path_buf(), obj));
}
self.compile_objects(&src_dst)?;
self.compile_objects(&objects)?;
self.assemble(lib_name, &dst.join(gnu_lib_name), &objects)?;
if self.get_target()?.contains("msvc") {
@ -827,7 +877,7 @@ impl Build {
}
#[cfg(feature = "parallel")]
fn compile_objects(&self, objs: &[(PathBuf, PathBuf)]) -> Result<(), Error> {
fn compile_objects(&self, objs: &[Object]) -> Result<(), Error> {
use self::rayon::prelude::*;
let mut cfg = rayon::Configuration::new();
@ -841,7 +891,7 @@ impl Build {
let results: Mutex<Vec<Result<(), Error>>> = Mutex::new(Vec::new());
objs.par_iter().with_max_len(1)
.for_each(|&(ref src, ref dst)| results.lock().unwrap().push(self.compile_object(src, dst)));
.for_each(|obj| results.lock().unwrap().push(self.compile_object(obj)));
// Check for any errors and return the first one found.
for result in results.into_inner().unwrap().iter() {
@ -854,15 +904,15 @@ impl Build {
}
#[cfg(not(feature = "parallel"))]
fn compile_objects(&self, objs: &[(PathBuf, PathBuf)]) -> Result<(), Error> {
for &(ref src, ref dst) in objs {
self.compile_object(src, dst)?;
fn compile_objects(&self, objs: &[Object]) -> Result<(), Error> {
for obj in objs {
self.compile_object(obj)?;
}
Ok(())
}
fn compile_object(&self, file: &Path, dst: &Path) -> Result<(), Error> {
let is_asm = file.extension().and_then(|s| s.to_str()) == Some("asm");
fn compile_object(&self, obj: &Object) -> Result<(), Error> {
let is_asm = obj.src.extension().and_then(|s| s.to_str()) == Some("asm");
let msvc = self.get_target()?.contains("msvc");
let (mut cmd, name) = if msvc && is_asm {
self.msvc_macro_assembler()?
@ -879,9 +929,9 @@ impl Build {
.to_string_lossy()
.into_owned())
};
command_add_output_file(&mut cmd, dst, msvc, is_asm);
command_add_output_file(&mut cmd, &obj.dst, msvc, is_asm);
cmd.arg(if msvc { "/c" } else { "-c" });
cmd.arg(file);
cmd.arg(&obj.src);
run(&mut cmd, &name)?;
Ok(())
@ -1220,11 +1270,12 @@ impl Build {
Ok((cmd, tool.to_string()))
}
fn assemble(&self, lib_name: &str, dst: &Path, objects: &[PathBuf]) -> Result<(), Error> {
fn assemble(&self, lib_name: &str, dst: &Path, objs: &[Object]) -> Result<(), Error> {
// Delete the destination if it exists as the `ar` tool at least on Unix
// appends to it, which we don't want.
let _ = fs::remove_file(&dst);
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 {
@ -1235,7 +1286,7 @@ impl Build {
out.push(dst);
run(cmd.arg(out)
.arg("/nologo")
.args(objects)
.args(&objects)
.args(&self.objects),
"lib.exe")?;
@ -1260,7 +1311,7 @@ impl Build {
run(self.cmd(&ar)
.arg("crs")
.arg(dst)
.args(objects)
.args(&objects)
.args(&self.objects),
&cmd)?;
}

Loading…
Cancel
Save