Skip to content

Commit d2a815e

Browse files
committed
improve cpp compiler execution
1 parent 9020e4c commit d2a815e

File tree

4 files changed

+138
-97
lines changed

4 files changed

+138
-97
lines changed

crates/intrinsic-test/src/arm/compile.rs

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
use crate::common::cli::ProcessedCli;
2-
use crate::common::compile_c::CompilationCommandBuilder;
3-
use crate::common::gen_c::compile_c_programs;
2+
use crate::common::compile_c::{CompilationCommandBuilder, CppCompilation};
43

5-
pub fn compile_c_arm(config: &ProcessedCli, intrinsics_name_list: &[String]) -> bool {
6-
let Some(ref cpp_compiler) = config.cpp_compiler else {
7-
return true;
8-
};
4+
pub fn build_cpp_compilation(config: &ProcessedCli) -> Option<CppCompilation> {
5+
let cpp_compiler = config.cpp_compiler.as_ref()?;
96

107
// -ffp-contract=off emulates Rust's approach of not fusing separate mul-add operations
118
let mut command = CompilationCommandBuilder::new()
@@ -60,16 +57,5 @@ pub fn compile_c_arm(config: &ProcessedCli, intrinsics_name_list: &[String]) ->
6057
command = command.add_extra_flag("-flax-vector-conversions");
6158
}
6259

63-
let compiler_commands = intrinsics_name_list
64-
.iter()
65-
.map(|intrinsic_name| {
66-
command
67-
.clone()
68-
.set_input_name(intrinsic_name)
69-
.set_output_name(intrinsic_name)
70-
.make_string()
71-
})
72-
.collect::<Vec<_>>();
73-
74-
compile_c_programs(&compiler_commands)
60+
Some(command.into_cpp_compilation())
7561
}

crates/intrinsic-test/src/arm/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ mod types;
77
use crate::common::SupportedArchitectureTest;
88
use crate::common::cli::ProcessedCli;
99
use crate::common::compare::compare_outputs;
10+
use crate::common::gen_c::compile_c_programs;
1011
use crate::common::gen_rust::compile_rust_programs;
1112
use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition};
1213
use crate::common::intrinsic_helpers::TypeKind;
@@ -66,7 +67,8 @@ impl SupportedArchitectureTest for ArmArchitectureTest {
6667
&[POLY128_OSTREAM_DEF],
6768
);
6869

69-
compile::compile_c_arm(&self.cli_options, intrinsics_name_list.as_slice())
70+
let pipeline = compile::build_cpp_compilation(&self.cli_options).unwrap();
71+
compile_c_programs(&pipeline, &intrinsics_name_list)
7072
}
7173

7274
fn build_rust_file(&self) -> bool {

crates/intrinsic-test/src/common/compile_c.rs

Lines changed: 110 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ pub struct CompilationCommandBuilder {
77
optimization: String,
88
include_paths: Vec<String>,
99
project_root: Option<String>,
10-
output: String,
11-
input: String,
1210
linker: Option<String>,
1311
extra_flags: Vec<String>,
1412
}
@@ -23,8 +21,6 @@ impl CompilationCommandBuilder {
2321
optimization: "2".to_string(),
2422
include_paths: Vec::new(),
2523
project_root: None,
26-
output: String::new(),
27-
input: String::new(),
2824
linker: None,
2925
extra_flags: Vec::new(),
3026
}
@@ -71,18 +67,6 @@ impl CompilationCommandBuilder {
7167
self
7268
}
7369

74-
/// The name of the output executable, without any suffixes
75-
pub fn set_output_name(mut self, path: &str) -> Self {
76-
self.output = path.to_string();
77-
self
78-
}
79-
80-
/// The name of the input C file, without any suffixes
81-
pub fn set_input_name(mut self, path: &str) -> Self {
82-
self.input = path.to_string();
83-
self
84-
}
85-
8670
pub fn set_linker(mut self, linker: String) -> Self {
8771
self.linker = Some(linker);
8872
self
@@ -100,55 +84,122 @@ impl CompilationCommandBuilder {
10084
}
10185

10286
impl CompilationCommandBuilder {
103-
pub fn make_string(self) -> String {
104-
let arch_flags = self.arch_flags.join("+");
87+
pub fn into_cpp_compilation(self) -> CppCompilation {
88+
let mut cpp_compiler = std::process::Command::new(self.compiler);
89+
90+
if let Some(project_root) = self.project_root {
91+
cpp_compiler.current_dir(project_root);
92+
}
93+
10594
let flags = std::env::var("CPPFLAGS").unwrap_or("".into());
106-
let project_root = self.project_root.unwrap_or_default();
107-
let project_root_str = project_root.as_str();
108-
let mut output = self.output.clone();
109-
if self.linker.is_some() {
110-
output += ".o"
111-
};
112-
let mut command = format!(
113-
"{} {flags} -march={arch_flags} \
114-
-O{} \
115-
-o {project_root}/{} \
116-
{project_root}/{}.cpp",
117-
self.compiler, self.optimization, output, self.input,
118-
);
119-
120-
command = command + " " + self.extra_flags.join(" ").as_str();
95+
cpp_compiler.args(flags.split_whitespace());
96+
97+
cpp_compiler.arg(format!("-march={}", self.arch_flags.join("+")));
98+
99+
cpp_compiler.arg(format!("-O{}", self.optimization));
100+
101+
cpp_compiler.args(self.extra_flags);
121102

122103
if let Some(target) = &self.target {
123-
command = command + " --target=" + target;
104+
cpp_compiler.arg(format!("--target={target}"));
124105
}
125106

126107
if let (Some(linker), Some(cxx_toolchain_dir)) = (&self.linker, &self.cxx_toolchain_dir) {
127-
let include_args = self
128-
.include_paths
129-
.iter()
130-
.map(|path| "--include-directory=".to_string() + cxx_toolchain_dir + path)
131-
.collect::<Vec<_>>()
132-
.join(" ");
133-
134-
command = command
135-
+ " -c "
136-
+ include_args.as_str()
137-
+ " && "
138-
+ linker
139-
+ " "
140-
+ project_root_str
141-
+ "/"
142-
+ &output
143-
+ " -o "
144-
+ project_root_str
145-
+ "/"
146-
+ &self.output
147-
+ " && rm "
148-
+ project_root_str
149-
+ "/"
150-
+ &output;
108+
cpp_compiler.args(
109+
self.include_paths
110+
.iter()
111+
.map(|path| "--include-directory=".to_string() + cxx_toolchain_dir + path),
112+
);
113+
114+
CppCompilation::CustomLinker {
115+
cpp_compiler,
116+
linker: linker.to_owned(),
117+
}
118+
} else {
119+
CppCompilation::Simple(cpp_compiler)
120+
}
121+
}
122+
}
123+
124+
pub enum CppCompilation {
125+
Simple(std::process::Command),
126+
CustomLinker {
127+
cpp_compiler: std::process::Command,
128+
linker: String,
129+
},
130+
}
131+
132+
fn clone_command(command: &std::process::Command) -> std::process::Command {
133+
let mut cmd = std::process::Command::new(command.get_program());
134+
if let Some(current_dir) = command.get_current_dir() {
135+
cmd.current_dir(current_dir);
136+
}
137+
cmd.args(command.get_args());
138+
139+
for (key, val) in command.get_envs() {
140+
cmd.env(key, val.unwrap_or_default());
141+
}
142+
143+
cmd
144+
}
145+
146+
impl CppCompilation {
147+
pub fn run(&self, inputs: &[String], output: &str) -> std::io::Result<std::process::Output> {
148+
match self {
149+
CppCompilation::Simple(command) => {
150+
let mut cmd = clone_command(command);
151+
cmd.args(inputs);
152+
cmd.args(["-o", output]);
153+
154+
cmd.output()
155+
}
156+
CppCompilation::CustomLinker {
157+
cpp_compiler,
158+
linker,
159+
} => {
160+
let object_file = &format!("{output}.o");
161+
162+
// Build an object file using the cpp compiler.
163+
let mut cmd = clone_command(cpp_compiler);
164+
cmd.args(inputs);
165+
cmd.args(["-c", "-o", object_file]);
166+
167+
let cpp_output = cmd.output()?;
168+
if !cpp_output.status.success() {
169+
error!("c++ compilaton failed");
170+
return Ok(cpp_output);
171+
}
172+
173+
trace!("using custom linker");
174+
175+
// Use the custom linker to turn the object file into an executable.
176+
let mut cmd = std::process::Command::new(linker);
177+
cmd.args([object_file, "-o", output]);
178+
179+
if let Some(current_dir) = cpp_compiler.get_current_dir() {
180+
cmd.current_dir(current_dir);
181+
}
182+
183+
for (key, val) in cpp_compiler.get_envs() {
184+
cmd.env(key, val.unwrap_or_default());
185+
}
186+
187+
let linker_output = cmd.output()?;
188+
if !linker_output.status.success() {
189+
error!("custom linker failed");
190+
return Ok(linker_output);
191+
}
192+
193+
trace!("removing {object_file}");
194+
let object_file_path = match cpp_compiler.get_current_dir() {
195+
Some(current_dir) => &format!("{}/{object_file}", current_dir.display()),
196+
None => object_file,
197+
};
198+
199+
std::fs::remove_file(object_file_path)?;
200+
201+
Ok(cpp_output)
202+
}
151203
}
152-
command
153204
}
154205
}

crates/intrinsic-test/src/common/gen_c.rs

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use itertools::Itertools;
22
use rayon::prelude::*;
33
use std::collections::BTreeMap;
4-
use std::process::Command;
4+
5+
use crate::common::compile_c::CppCompilation;
56

67
use super::argument::Argument;
78
use super::indentation::Indentation;
@@ -62,29 +63,30 @@ int main(int argc, char **argv) {{
6263
)
6364
}
6465

65-
pub fn compile_c_programs(compiler_commands: &[String]) -> bool {
66-
compiler_commands
66+
pub fn compile_c_programs(pipeline: &CppCompilation, intrinsics: &[String]) -> bool {
67+
intrinsics
6768
.par_iter()
68-
.map(|compiler_command| {
69-
let output = Command::new("sh").arg("-c").arg(compiler_command).output();
70-
if let Ok(output) = output {
71-
if output.status.success() {
72-
true
73-
} else {
74-
error!(
75-
"Failed to compile code for intrinsics: \n\nstdout:\n{}\n\nstderr:\n{}",
69+
.map(
70+
|intrinsic| match pipeline.run(&[format!("{intrinsic}.cpp")], intrinsic) {
71+
Ok(output) if output.status.success() => Ok(()),
72+
Ok(output) => {
73+
let msg = format!(
74+
"Failed to compile code for intrinsic `{intrinsic}`: \n\nstdout:\n{}\n\nstderr:\n{}",
7675
std::str::from_utf8(&output.stdout).unwrap_or(""),
7776
std::str::from_utf8(&output.stderr).unwrap_or("")
7877
);
79-
false
78+
error!("{msg}");
79+
80+
Err(msg)
8081
}
81-
} else {
82-
error!("Command failed: {output:#?}");
83-
false
84-
}
85-
})
86-
.find_any(|x| !x)
87-
.is_none()
82+
Err(e) => {
83+
error!("command for `{intrinsic}` failed with IO error: {e:?}");
84+
Err(e.to_string())
85+
}
86+
},
87+
)
88+
.collect::<Result<(), String>>()
89+
.is_ok()
8890
}
8991

9092
// Creates directory structure and file path mappings

0 commit comments

Comments
 (0)