#[derive(Clone)] pub struct CompilationCommandBuilder { compiler: String, target: Option, cxx_toolchain_dir: Option, arch_flags: Vec, optimization: String, include_paths: Vec, project_root: Option, output: String, input: String, linker: Option, extra_flags: Vec, } impl CompilationCommandBuilder { pub fn new() -> Self { Self { compiler: String::new(), target: None, cxx_toolchain_dir: None, arch_flags: Vec::new(), optimization: "2".to_string(), include_paths: Vec::new(), project_root: None, output: String::new(), input: String::new(), linker: None, extra_flags: Vec::new(), } } pub fn set_compiler(mut self, compiler: &str) -> Self { self.compiler = compiler.to_string(); self } pub fn set_target(mut self, target: &str) -> Self { self.target = Some(target.to_string()); self } pub fn set_cxx_toolchain_dir(mut self, path: Option<&str>) -> Self { self.cxx_toolchain_dir = path.map(|p| p.to_string()); self } pub fn add_arch_flags(mut self, flags: Vec<&str>) -> Self { let mut new_arch_flags = flags.into_iter().map(|v| v.to_string()).collect(); self.arch_flags.append(&mut new_arch_flags); self } pub fn set_opt_level(mut self, optimization: &str) -> Self { self.optimization = optimization.to_string(); self } /// Sets a list of include paths for compilation. /// The paths that are passed must be relative to the /// "cxx_toolchain_dir" directory path. pub fn set_include_paths(mut self, paths: Vec<&str>) -> Self { self.include_paths = paths.into_iter().map(|path| path.to_string()).collect(); self } /// Sets the root path of all the generated test files. pub fn set_project_root(mut self, path: &str) -> Self { self.project_root = Some(path.to_string()); self } /// The name of the output executable, without any suffixes pub fn set_output_name(mut self, path: &str) -> Self { self.output = path.to_string(); self } /// The name of the input C file, without any suffixes pub fn set_input_name(mut self, path: &str) -> Self { self.input = path.to_string(); self } pub fn set_linker(mut self, linker: String) -> Self { self.linker = Some(linker); self } pub fn add_extra_flags(mut self, flags: Vec<&str>) -> Self { let mut flags: Vec = flags.into_iter().map(|f| f.to_string()).collect(); self.extra_flags.append(&mut flags); self } pub fn add_extra_flag(self, flag: &str) -> Self { self.add_extra_flags(vec![flag]) } } impl CompilationCommandBuilder { pub fn to_string(self) -> String { let arch_flags = self.arch_flags.join("+"); let flags = std::env::var("CPPFLAGS").unwrap_or("".into()); let project_root = self.project_root.unwrap_or(String::new()); let project_root_str = project_root.as_str(); let mut output = self.output.clone(); if self.linker.is_some() { output += ".o" }; let mut command = format!( "{} {flags} -march={arch_flags} \ -O{} \ -o {project_root}/{} \ {project_root}/{}.cpp", self.compiler, self.optimization, output, self.input, ); command = command + " " + self.extra_flags.join(" ").as_str(); if let Some(target) = &self.target { command = command + " --target=" + target; } if let (Some(linker), Some(cxx_toolchain_dir)) = (&self.linker, &self.cxx_toolchain_dir) { let include_args = self .include_paths .iter() .map(|path| "--include-directory=".to_string() + cxx_toolchain_dir + path) .collect::>() .join(" "); command = command + " -c " + include_args.as_str() + " && " + linker + " " + project_root_str + "/" + &output + " -o " + project_root_str + "/" + &self.output + " && rm " + project_root_str + "/" + &output; } command } }