diff options
author | syn <isaqtm@gmail.com> | 2020-12-08 10:35:52 +0300 |
---|---|---|
committer | syn <isaqtm@gmail.com> | 2020-12-08 10:35:52 +0300 |
commit | 69c1e85be895bbcfcbfed6f3154bd552d46858f4 (patch) | |
tree | 546e95e874004a87c2c241a36ef9a9ac775a30af /src | |
parent | 4a70743d725693c5980b157a819c4e6fa80b3e01 (diff) | |
download | evr-69c1e85be895bbcfcbfed6f3154bd552d46858f4.tar.gz |
Add C backend
Diffstat (limited to 'src')
-rw-r--r-- | src/backends/clang_c.rs | 94 | ||||
-rw-r--r-- | src/backends/mod.rs | 2 | ||||
-rw-r--r-- | src/conf.rs | 13 |
3 files changed, 107 insertions, 2 deletions
diff --git a/src/backends/clang_c.rs b/src/backends/clang_c.rs new file mode 100644 index 0000000..1aa39e4 --- /dev/null +++ b/src/backends/clang_c.rs @@ -0,0 +1,94 @@ +use serde_derive::Deserialize; +use crate::backends::{ Backend, mk_tmp_dir, RunError }; +use std::path::{ Path, PathBuf }; +use std::io::{ Result as IoResult, Error, ErrorKind }; +use std::process::Command; +use std::collections::hash_map::DefaultHasher; +use std::hash::{ Hash, Hasher }; +use crate::wait::{ ChildExitStatus, wait_child }; +use std::time::Duration; +use crate::serde_duration::deserialize_duration; + + +#[derive(Debug, Deserialize, Default)] +pub struct ClangCBackend { + template: Option<String>, + + #[serde(default)] + args: Vec<String>, + + #[serde(default = "default_cc")] + cc: String, + + #[serde(default = "default_timeout", deserialize_with = "deserialize_duration")] + timeout: Duration +} + + +fn default_cc() -> String { + "clang".to_string() +} + +fn default_timeout() -> Duration { + Duration::from_secs(1) +} + + +fn get_binary_by_filename(fname: &Path) -> IoResult<PathBuf> { + let hashed_fname = { + let mut hasher = DefaultHasher::new(); + fname.hash(&mut hasher); + format!("{:x}", hasher.finish()) + }; + + Ok(mk_tmp_dir()?.join(hashed_fname)) +} + + +impl ClangCBackend { + fn build(&self, fname: &Path) -> IoResult<PathBuf> { + let binary_fname = get_binary_by_filename(fname)?; + let get_mtime = |file| { + std::fs::metadata(file)? + .modified() + }; + + let src_mod = get_mtime(fname); + let binary_mod = get_mtime(&binary_fname); + + if src_mod.is_err() || binary_mod.is_err() || src_mod.unwrap() > binary_mod.unwrap() { + let clang_status = Command::new(&self.cc) + .arg("-x").arg("c") + .arg(fname.clone().as_os_str()) + .arg("-o").arg(&binary_fname) + .args(&self.args) + .status()?; + + if !clang_status.success() { + return Err(Error::new(ErrorKind::Other, + "could not compile")); + } + } + + Ok(binary_fname) + } +} + + +impl Backend for ClangCBackend { + fn get_template(&self) -> Option<&str> { + match self.template { + Some(ref t) => Some(t), + None => None + } + } + + fn run(&self, fname: &Path) -> Result<ChildExitStatus, RunError> { + let binary_fname = self.build(fname)?; + + let proc = Command::new(&binary_fname) + .spawn()?; + + Ok(wait_child(proc, self.timeout, std::time::Instant::now())?) + } +} diff --git a/src/backends/mod.rs b/src/backends/mod.rs index a5d2d28..50bef36 100644 --- a/src/backends/mod.rs +++ b/src/backends/mod.rs @@ -6,9 +6,11 @@ use crate::wait::ChildExitStatus; pub mod python; pub mod clang; +pub mod clang_c; pub use python::PythonBackend; pub use clang::ClangBackend; +pub use clang_c::ClangCBackend; pub mod run_error; pub use run_error::RunError; diff --git a/src/conf.rs b/src/conf.rs index 26a4832..3649a50 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -5,7 +5,12 @@ use toml::de; type Error = std::io::Error; use std::io::ErrorKind; -use crate::backends::{ Backend, PythonBackend, ClangBackend }; +use crate::backends::{ + Backend, + PythonBackend, + ClangBackend, + ClangCBackend, +}; #[derive(Debug, Deserialize)] @@ -17,7 +22,10 @@ pub struct Conf { python: PythonBackend, #[serde(default)] - clang: ClangBackend + clang: ClangBackend, + + #[serde(default)] + clang_c: ClangCBackend, } @@ -36,6 +44,7 @@ impl Conf { match ext { "py" => Some(Box::new(&self.python)), "cc" | "cpp" | "cxx" => Some(Box::new(&self.clang)), + "c" => Some(Box::new(&self.clang_c)), _ => None } } |