Browse Source

Cleanup after merging with latest master.

cl-test
Peter Jin 7 years ago
parent
commit
79a2b73931
  1. 16
      README.md
  2. 120
      src/lib.rs

16
README.md

@ -159,18 +159,26 @@ linked to the crate target.
## CUDA C++ support ## CUDA C++ support
`gcc-rs` also supports compiling CUDA C++ libraries by using the `cuda` method `cc-rs` also supports compiling CUDA C++ libraries by using the `cuda` method
on `Build` (currently for GNU/Clang toolchains only): on `Build` (currently for GNU/Clang toolchains only):
```rust,no_run ```rust,no_run
extern crate gcc; extern crate cc;
fn main() { fn main() {
gcc::Build::new() cc::Build::new()
// Switch to CUDA C++ library compilation using NVCC. // Switch to CUDA C++ library compilation using NVCC.
.cuda(true) .cuda(true)
// Generate code for Maxwell architecture. // Generate code for Maxwell (GTX 970, 980, 980 Ti, Titan X).
.flag("-gencode").flag("arch=compute_52,code=sm_52") .flag("-gencode").flag("arch=compute_52,code=sm_52")
// Generate code for Maxwell (Jetson TX1).
.flag("-gencode").flag("arch=compute_53,code=sm_53")
// Generate code for Pascal (GTX 1070, 1080, 1080 Ti, Titan Xp).
.flag("-gencode").flag("arch=compute_61,code=sm_61")
// Generate code for Pascal (Tesla P100).
.flag("-gencode").flag("arch=compute_60,code=sm_60")
// Generate code for Pascal (Jetson TX2).
.flag("-gencode").flag("arch=compute_62,code=sm_62")
.file("bar.cu") .file("bar.cu")
.compile("libbar.a"); .compile("libbar.a");
} }

120
src/lib.rs

@ -98,7 +98,6 @@ pub struct Build {
flags: Vec<String>, flags: Vec<String>,
flags_supported: Vec<String>, flags_supported: Vec<String>,
files: Vec<PathBuf>, files: Vec<PathBuf>,
dialect: Dialect,
cpp: bool, cpp: bool,
cpp_link_stdlib: Option<Option<String>>, cpp_link_stdlib: Option<Option<String>>,
cpp_set_stdlib: Option<String>, cpp_set_stdlib: Option<String>,
@ -174,6 +173,7 @@ pub struct Tool {
args: Vec<OsString>, args: Vec<OsString>,
env: Vec<(OsString, OsString)>, env: Vec<(OsString, OsString)>,
family: ToolFamily, family: ToolFamily,
cuda: bool,
} }
/// Represents the family of tools this tool belongs to. /// Represents the family of tools this tool belongs to.
@ -257,52 +257,19 @@ 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. /// Represents an object.
/// ///
/// This is a source file -> object file pair, with an associated language /// This is a source file -> object file pair.
/// dialect.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Object { pub struct Object {
dialect: Dialect,
src: PathBuf, src: PathBuf,
dst: PathBuf, dst: PathBuf,
} }
impl Object { impl Object {
/// Create a new source file -> object file pair, while autodetecting the /// Create a new source file -> object file pair.
/// dialect from the source file extension. fn new(src: PathBuf, dst: PathBuf) -> Object {
pub fn new(src: PathBuf, dst: PathBuf) -> Object {
Object { Object {
dialect: autodetect_ext(&src),
src: src, src: src,
dst: dst, dst: dst,
} }
@ -325,7 +292,6 @@ impl Build {
files: Vec::new(), files: Vec::new(),
shared_flag: None, shared_flag: None,
static_flag: None, static_flag: None,
dialect: Dialect::C,
cpp: false, cpp: false,
cpp_link_stdlib: None, cpp_link_stdlib: None,
cpp_set_stdlib: None, cpp_set_stdlib: None,
@ -436,7 +402,7 @@ impl Build {
.opt_level(0) .opt_level(0)
.host(&target) .host(&target)
.debug(false) .debug(false)
.cpp(self.cpp); .cpp(self.cpp)
.cuda(self.cuda); .cuda(self.cuda);
let compiler = cfg.try_get_compiler()?; let compiler = cfg.try_get_compiler()?;
let mut cmd = compiler.to_command(); let mut cmd = compiler.to_command();
@ -511,13 +477,6 @@ impl Build {
/// Add a file which will be compiled /// Add a file which will be compiled
pub fn file<P: AsRef<Path>>(&mut self, p: P) -> &mut Build { pub fn file<P: AsRef<Path>>(&mut self, p: P) -> &mut Build {
self.files.push(p.as_ref().to_path_buf()); self.files.push(p.as_ref().to_path_buf());
match (self.dialect, autodetect_ext(p.as_ref())) {
(_, Dialect::C) => {}
(Dialect::C, Dialect::Cpp) |
(Dialect::Cpp, Dialect::Cpp) => { self.cpp(true); }
(Dialect::Cuda, Dialect::Cpp) => {}
(_, Dialect::Cuda) => { self.cuda(true); }
}
self self
} }
@ -539,9 +498,6 @@ impl Build {
/// `true`. /// `true`.
pub fn cpp(&mut self, cpp: bool) -> &mut Build { pub fn cpp(&mut self, cpp: bool) -> &mut Build {
self.cpp = cpp; self.cpp = cpp;
if cpp {
self.dialect = Dialect::Cpp;
}
self self
} }
@ -556,7 +512,6 @@ impl Build {
pub fn cuda(&mut self, cuda: bool) -> &mut Build { pub fn cuda(&mut self, cuda: bool) -> &mut Build {
self.cuda = cuda; self.cuda = cuda;
if cuda { if cuda {
self.dialect = Dialect::Cuda;
self.cpp = true; self.cpp = true;
} }
self self
@ -929,8 +884,8 @@ impl Build {
let results: Mutex<Vec<Result<(), Error>>> = Mutex::new(Vec::new()); let results: Mutex<Vec<Result<(), Error>>> = Mutex::new(Vec::new());
objs.par_iter().with_max_len(1).for_each( objs.par_iter().with_max_len(1).for_each(
|&(ref src, ref dst)| { |obj| {
let res = self.compile_object(src, dst); let res = self.compile_object(obj);
results.lock().unwrap().push(res) results.lock().unwrap().push(res)
}, },
); );
@ -1066,11 +1021,6 @@ impl Build {
let target = self.get_target()?; let target = self.get_target()?;
let mut cmd = self.get_base_compiler()?; let mut cmd = self.get_base_compiler()?;
let nvcc = cmd.path
.file_name()
.and_then(|p| p.to_str())
.map(|p| p.contains("nvcc"))
.unwrap_or(false);
// Non-target flags // Non-target flags
// If the flag is not conditioned on target variable, it belongs here :) // If the flag is not conditioned on target variable, it belongs here :)
@ -1113,13 +1063,10 @@ impl Build {
cmd.args.push(format!("-O{}", opt_level).into()); cmd.args.push(format!("-O{}", opt_level).into());
} }
cmd.nvcc_wrap_arg(self.cuda); cmd.push_cc_arg("-ffunction-sections".into());
cmd.args.push("-ffunction-sections".into()); cmd.push_cc_arg("-fdata-sections".into());
cmd.nvcc_wrap_arg(self.cuda);
cmd.args.push("-fdata-sections".into());
if self.pic.unwrap_or(!target.contains("windows-gnu")) { if self.pic.unwrap_or(!target.contains("windows-gnu")) {
cmd.nvcc_wrap_arg(self.cuda); cmd.push_cc_arg("-fPIC".into());
cmd.args.push("-fPIC".into());
} }
} }
} }
@ -1129,11 +1076,11 @@ impl Build {
if self.get_debug() { if self.get_debug() {
if self.cuda { if self.cuda {
let nvcc_debug_arg = cmd.family.nvcc_debug_flag().into(); let nvcc_debug_flag = cmd.family.nvcc_debug_flag().into();
cmd.args.push(nvcc_debug_arg); cmd.args.push(nvcc_debug_flag);
} }
cmd.nvcc_wrap_arg(self.cuda); let debug_flag = cmd.family.debug_flag().into();
cmd.args.push(cmd.family.debug_flag().into()); cmd.push_cc_arg(debug_flag);
} }
// Target flags // Target flags
@ -1248,8 +1195,7 @@ impl Build {
(None, _) => {} (None, _) => {}
(Some(stdlib), ToolFamily::Gnu) | (Some(stdlib), ToolFamily::Gnu) |
(Some(stdlib), ToolFamily::Clang) => { (Some(stdlib), ToolFamily::Clang) => {
cmd.nvcc_wrap_arg(self.cuda); cmd.push_cc_arg(format!("-stdlib=lib{}", stdlib).into());
cmd.args.push(format!("-stdlib=lib{}", stdlib).into());
} }
_ => { _ => {
println!( println!(
@ -1268,7 +1214,7 @@ impl Build {
if self.warnings { if self.warnings {
for flag in cmd.family.warnings_flags().iter() { for flag in cmd.family.warnings_flags().iter() {
cmd.args.push(flag.into()); cmd.push_cc_arg(flag.into());
} }
} }
@ -1278,8 +1224,7 @@ impl Build {
for flag in self.flags_supported.iter() { for flag in self.flags_supported.iter() {
if self.is_flag_supported(flag).unwrap_or(false) { if self.is_flag_supported(flag).unwrap_or(false) {
cmd.nvcc_wrap_arg(self.cuda); cmd.push_cc_arg(flag.into());
cmd.args.push(flag.into());
} }
} }
@ -1296,16 +1241,9 @@ impl Build {
} }
} }
if self.warnings {
for flag in cmd.family.warnings_flags().iter() {
cmd.nvcc_wrap_arg(self.cuda);
cmd.args.push(flag.into());
}
}
if self.warnings_into_errors { if self.warnings_into_errors {
cmd.nvcc_wrap_arg(self.cuda); let warnings_to_errors_flag = cmd.family.warnings_to_errors_flag().into();
cmd.args.push(cmd.family.warnings_to_errors_flag().into()); cmd.push_cc_arg(warnings_to_errors_flag);
} }
Ok(cmd) Ok(cmd)
@ -1361,9 +1299,7 @@ impl Build {
let mut out = OsString::from("/OUT:"); let mut out = OsString::from("/OUT:");
out.push(dst); out.push(dst);
run( run(
cmd.arg(out).arg("/nologo").args(objects).args( cmd.arg(out).arg("/nologo").args(&objects).args(&self.objects),
&self.objects,
),
"lib.exe", "lib.exe",
)?; )?;
@ -1387,7 +1323,7 @@ impl Build {
} else { } else {
let (mut ar, cmd) = self.get_ar()?; let (mut ar, cmd) = self.get_ar()?;
run( run(
ar.arg("crs").arg(dst).args(objects).args(&self.objects), ar.arg("crs").arg(dst).args(&objects).args(&self.objects),
&cmd, &cmd,
)?; )?;
} }
@ -1590,7 +1526,7 @@ impl Build {
Err(_) => "nvcc".into(), Err(_) => "nvcc".into(),
Ok(nvcc) => nvcc, Ok(nvcc) => nvcc,
}; };
let mut nvcc_tool = Tool::new(PathBuf::from(nvcc)); let mut nvcc_tool = Tool::with_features(PathBuf::from(nvcc), self.cuda);
nvcc_tool.args.push(format!("-ccbin={}", tool.path.display()).into()); nvcc_tool.args.push(format!("-ccbin={}", tool.path.display()).into());
nvcc_tool nvcc_tool
} else { } else {
@ -1767,6 +1703,10 @@ impl Default for Build {
impl Tool { impl Tool {
fn new(path: PathBuf) -> Tool { fn new(path: PathBuf) -> Tool {
Tool::with_features(path, false)
}
fn with_features(path: PathBuf, cuda: bool) -> Tool {
// Try to detect family of the tool from its name, falling back to Gnu. // Try to detect family of the tool from its name, falling back to Gnu.
let family = if let Some(fname) = path.file_name().and_then(|p| p.to_str()) { let family = if let Some(fname) = path.file_name().and_then(|p| p.to_str()) {
if fname.contains("clang") { if fname.contains("clang") {
@ -1786,18 +1726,20 @@ impl Tool {
args: Vec::new(), args: Vec::new(),
env: Vec::new(), env: Vec::new(),
family: family, family: family,
cuda: cuda,
} }
} }
/// Optionally appends the NVCC wrapper flag "-Xcompiler". /// Add a flag, and optionally prepend the NVCC wrapper flag "-Xcompiler".
/// ///
/// Currently this is only used for compiling CUDA sources, since NVCC only /// Currently this is only used for compiling CUDA sources, since NVCC only
/// accepts a limited set of GNU-like flags, and the rest must be prefixed /// accepts a limited set of GNU-like flags, and the rest must be prefixed
/// with a "-Xcompiler" flag to get passed to the underlying C++ compiler. /// with a "-Xcompiler" flag to get passed to the underlying C++ compiler.
fn nvcc_wrap_arg(&mut self, cuda: bool) { fn push_cc_arg(&mut self, flag: OsString) {
if cuda { if self.cuda {
self.args.push(self.family.nvcc_redirect_flag().into()); self.args.push(self.family.nvcc_redirect_flag().into());
} }
self.args.push(flag);
} }
/// Converts this compiler into a `Command` that's ready to be run. /// Converts this compiler into a `Command` that's ready to be run.

Loading…
Cancel
Save