|
|
@ -98,7 +98,6 @@ pub struct Build { |
|
|
|
flags: Vec<String>, |
|
|
|
flags_supported: Vec<String>, |
|
|
|
files: Vec<PathBuf>, |
|
|
|
dialect: Dialect, |
|
|
|
cpp: bool, |
|
|
|
cpp_link_stdlib: Option<Option<String>>, |
|
|
|
cpp_set_stdlib: Option<String>, |
|
|
@ -174,6 +173,7 @@ pub struct Tool { |
|
|
|
args: Vec<OsString>, |
|
|
|
env: Vec<(OsString, OsString)>, |
|
|
|
family: ToolFamily, |
|
|
|
cuda: bool, |
|
|
|
} |
|
|
|
|
|
|
|
/// 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.
|
|
|
|
///
|
|
|
|
/// This is a source file -> object file pair, with an associated language
|
|
|
|
/// dialect.
|
|
|
|
/// This is a source file -> object file pair.
|
|
|
|
#[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 { |
|
|
|
/// Create a new source file -> object file pair.
|
|
|
|
fn new(src: PathBuf, dst: PathBuf) -> Object { |
|
|
|
Object { |
|
|
|
dialect: autodetect_ext(&src), |
|
|
|
src: src, |
|
|
|
dst: dst, |
|
|
|
} |
|
|
@ -325,7 +292,6 @@ impl Build { |
|
|
|
files: Vec::new(), |
|
|
|
shared_flag: None, |
|
|
|
static_flag: None, |
|
|
|
dialect: Dialect::C, |
|
|
|
cpp: false, |
|
|
|
cpp_link_stdlib: None, |
|
|
|
cpp_set_stdlib: None, |
|
|
@ -436,7 +402,7 @@ impl Build { |
|
|
|
.opt_level(0) |
|
|
|
.host(&target) |
|
|
|
.debug(false) |
|
|
|
.cpp(self.cpp); |
|
|
|
.cpp(self.cpp) |
|
|
|
.cuda(self.cuda); |
|
|
|
let compiler = cfg.try_get_compiler()?; |
|
|
|
let mut cmd = compiler.to_command(); |
|
|
@ -511,13 +477,6 @@ impl Build { |
|
|
|
/// Add a file which will be compiled
|
|
|
|
pub fn file<P: AsRef<Path>>(&mut self, p: P) -> &mut Build { |
|
|
|
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 |
|
|
|
} |
|
|
|
|
|
|
@ -539,9 +498,6 @@ impl Build { |
|
|
|
/// `true`.
|
|
|
|
pub fn cpp(&mut self, cpp: bool) -> &mut Build { |
|
|
|
self.cpp = cpp; |
|
|
|
if cpp { |
|
|
|
self.dialect = Dialect::Cpp; |
|
|
|
} |
|
|
|
self |
|
|
|
} |
|
|
|
|
|
|
@ -556,7 +512,6 @@ impl Build { |
|
|
|
pub fn cuda(&mut self, cuda: bool) -> &mut Build { |
|
|
|
self.cuda = cuda; |
|
|
|
if cuda { |
|
|
|
self.dialect = Dialect::Cuda; |
|
|
|
self.cpp = true; |
|
|
|
} |
|
|
|
self |
|
|
@ -929,8 +884,8 @@ 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)| { |
|
|
|
let res = self.compile_object(src, dst); |
|
|
|
|obj| { |
|
|
|
let res = self.compile_object(obj); |
|
|
|
results.lock().unwrap().push(res) |
|
|
|
}, |
|
|
|
); |
|
|
@ -1066,11 +1021,6 @@ impl Build { |
|
|
|
let target = self.get_target()?; |
|
|
|
|
|
|
|
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
|
|
|
|
// 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.nvcc_wrap_arg(self.cuda); |
|
|
|
cmd.args.push("-ffunction-sections".into()); |
|
|
|
cmd.nvcc_wrap_arg(self.cuda); |
|
|
|
cmd.args.push("-fdata-sections".into()); |
|
|
|
cmd.push_cc_arg("-ffunction-sections".into()); |
|
|
|
cmd.push_cc_arg("-fdata-sections".into()); |
|
|
|
if self.pic.unwrap_or(!target.contains("windows-gnu")) { |
|
|
|
cmd.nvcc_wrap_arg(self.cuda); |
|
|
|
cmd.args.push("-fPIC".into()); |
|
|
|
cmd.push_cc_arg("-fPIC".into()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -1129,11 +1076,11 @@ impl Build { |
|
|
|
|
|
|
|
if self.get_debug() { |
|
|
|
if self.cuda { |
|
|
|
let nvcc_debug_arg = cmd.family.nvcc_debug_flag().into(); |
|
|
|
cmd.args.push(nvcc_debug_arg); |
|
|
|
let nvcc_debug_flag = cmd.family.nvcc_debug_flag().into(); |
|
|
|
cmd.args.push(nvcc_debug_flag); |
|
|
|
} |
|
|
|
cmd.nvcc_wrap_arg(self.cuda); |
|
|
|
cmd.args.push(cmd.family.debug_flag().into()); |
|
|
|
let debug_flag = cmd.family.debug_flag().into(); |
|
|
|
cmd.push_cc_arg(debug_flag); |
|
|
|
} |
|
|
|
|
|
|
|
// Target flags
|
|
|
@ -1248,8 +1195,7 @@ impl Build { |
|
|
|
(None, _) => {} |
|
|
|
(Some(stdlib), ToolFamily::Gnu) | |
|
|
|
(Some(stdlib), ToolFamily::Clang) => { |
|
|
|
cmd.nvcc_wrap_arg(self.cuda); |
|
|
|
cmd.args.push(format!("-stdlib=lib{}", stdlib).into()); |
|
|
|
cmd.push_cc_arg(format!("-stdlib=lib{}", stdlib).into()); |
|
|
|
} |
|
|
|
_ => { |
|
|
|
println!( |
|
|
@ -1268,7 +1214,7 @@ impl Build { |
|
|
|
|
|
|
|
if self.warnings { |
|
|
|
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() { |
|
|
|
if self.is_flag_supported(flag).unwrap_or(false) { |
|
|
|
cmd.nvcc_wrap_arg(self.cuda); |
|
|
|
cmd.args.push(flag.into()); |
|
|
|
cmd.push_cc_arg(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 { |
|
|
|
cmd.nvcc_wrap_arg(self.cuda); |
|
|
|
cmd.args.push(cmd.family.warnings_to_errors_flag().into()); |
|
|
|
let warnings_to_errors_flag = cmd.family.warnings_to_errors_flag().into(); |
|
|
|
cmd.push_cc_arg(warnings_to_errors_flag); |
|
|
|
} |
|
|
|
|
|
|
|
Ok(cmd) |
|
|
@ -1361,9 +1299,7 @@ impl Build { |
|
|
|
let mut out = OsString::from("/OUT:"); |
|
|
|
out.push(dst); |
|
|
|
run( |
|
|
|
cmd.arg(out).arg("/nologo").args(objects).args( |
|
|
|
&self.objects, |
|
|
|
), |
|
|
|
cmd.arg(out).arg("/nologo").args(&objects).args(&self.objects), |
|
|
|
"lib.exe", |
|
|
|
)?; |
|
|
|
|
|
|
@ -1387,7 +1323,7 @@ impl Build { |
|
|
|
} else { |
|
|
|
let (mut ar, cmd) = self.get_ar()?; |
|
|
|
run( |
|
|
|
ar.arg("crs").arg(dst).args(objects).args(&self.objects), |
|
|
|
ar.arg("crs").arg(dst).args(&objects).args(&self.objects), |
|
|
|
&cmd, |
|
|
|
)?; |
|
|
|
} |
|
|
@ -1590,7 +1526,7 @@ impl Build { |
|
|
|
Err(_) => "nvcc".into(), |
|
|
|
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 |
|
|
|
} else { |
|
|
@ -1767,6 +1703,10 @@ impl Default for Build { |
|
|
|
|
|
|
|
impl 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.
|
|
|
|
let family = if let Some(fname) = path.file_name().and_then(|p| p.to_str()) { |
|
|
|
if fname.contains("clang") { |
|
|
@ -1786,18 +1726,20 @@ impl Tool { |
|
|
|
args: Vec::new(), |
|
|
|
env: Vec::new(), |
|
|
|
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
|
|
|
|
/// 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.
|
|
|
|
fn nvcc_wrap_arg(&mut self, cuda: bool) { |
|
|
|
if cuda { |
|
|
|
fn push_cc_arg(&mut self, flag: OsString) { |
|
|
|
if self.cuda { |
|
|
|
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.
|
|
|
|