1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
#[derive(Clone)]
pub struct CompilationCommandBuilder {
compiler: String,
target: Option<String>,
cxx_toolchain_dir: Option<String>,
arch_flags: Vec<String>,
optimization: String,
project_root: Option<String>,
extra_flags: Vec<String>,
}
impl CompilationCommandBuilder {
pub fn new() -> Self {
Self {
compiler: String::new(),
target: None,
cxx_toolchain_dir: None,
arch_flags: Vec::new(),
optimization: "2".to_string(),
project_root: 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 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
}
pub fn add_extra_flags(mut self, flags: Vec<&str>) -> Self {
let mut flags: Vec<String> = 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 into_cpp_compilation(self) -> CppCompilation {
let mut cpp_compiler = std::process::Command::new(self.compiler);
if let Some(project_root) = self.project_root {
cpp_compiler.current_dir(project_root);
}
let flags = std::env::var("CPPFLAGS").unwrap_or("".into());
cpp_compiler.args(flags.split_whitespace());
cpp_compiler.arg(format!("-march={}", self.arch_flags.join("+")));
cpp_compiler.arg(format!("-O{}", self.optimization));
cpp_compiler.args(self.extra_flags);
if let Some(target) = &self.target {
cpp_compiler.arg(format!("--target={target}"));
}
CppCompilation(cpp_compiler)
}
}
pub struct CppCompilation(std::process::Command);
fn clone_command(command: &std::process::Command) -> std::process::Command {
let mut cmd = std::process::Command::new(command.get_program());
if let Some(current_dir) = command.get_current_dir() {
cmd.current_dir(current_dir);
}
cmd.args(command.get_args());
for (key, val) in command.get_envs() {
cmd.env(key, val.unwrap_or_default());
}
cmd
}
impl CppCompilation {
pub fn command_mut(&mut self) -> &mut std::process::Command {
&mut self.0
}
pub fn compile_object_file(
&self,
input: &str,
output: &str,
) -> std::io::Result<std::process::Output> {
let mut cmd = clone_command(&self.0);
cmd.args([input, "-c", "-o", output]);
cmd.output()
}
pub fn link_executable(
&self,
inputs: impl Iterator<Item = String>,
output: &str,
) -> std::io::Result<std::process::Output> {
let mut cmd = clone_command(&self.0);
cmd.args(inputs);
cmd.args(["-o", output]);
cmd.output()
}
}
|