diff options
| author | Folkert de Vries <folkert@folkertdev.nl> | 2025-07-10 20:30:36 +0200 |
|---|---|---|
| committer | Folkert de Vries <folkert@folkertdev.nl> | 2025-07-18 11:38:18 +0200 |
| commit | 75887cf99557c84ebb64077a1b3f96ad8a597c22 (patch) | |
| tree | 046ae9431659451833bf6e6c1b7fd4c77a95250a /library/stdarch/crates/intrinsic-test | |
| parent | 668fdbe41edba8bda2100a71fe412ab62322b8d5 (diff) | |
| download | rust-75887cf99557c84ebb64077a1b3f96ad8a597c22.tar.gz rust-75887cf99557c84ebb64077a1b3f96ad8a597c22.zip | |
improve cpp compiler execution
Diffstat (limited to 'library/stdarch/crates/intrinsic-test')
4 files changed, 92 insertions, 144 deletions
diff --git a/library/stdarch/crates/intrinsic-test/src/arm/compile.rs b/library/stdarch/crates/intrinsic-test/src/arm/compile.rs index a90caf367ca..48a8ed950e3 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/compile.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/compile.rs @@ -1,11 +1,8 @@ use crate::common::cli::ProcessedCli; -use crate::common::compile_c::CompilationCommandBuilder; -use crate::common::gen_c::compile_c_programs; +use crate::common::compile_c::{CompilationCommandBuilder, CppCompilation}; -pub fn compile_c_arm(config: &ProcessedCli, intrinsics_name_list: &[String]) -> bool { - let Some(ref cpp_compiler) = config.cpp_compiler else { - return true; - }; +pub fn build_cpp_compilation(config: &ProcessedCli) -> Option<CppCompilation> { + let cpp_compiler = config.cpp_compiler.as_ref()?; // -ffp-contract=off emulates Rust's approach of not fusing separate mul-add operations let mut command = CompilationCommandBuilder::new() @@ -21,15 +18,12 @@ pub fn compile_c_arm(config: &ProcessedCli, intrinsics_name_list: &[String]) -> command = command.add_arch_flags(vec!["faminmax", "lut", "sha3"]); } - /* - * clang++ cannot link an aarch64_be object file, so we invoke - * aarch64_be-unknown-linux-gnu's C++ linker. This ensures that we - * are testing the intrinsics against LLVM. - * - * Note: setting `--sysroot=<...>` which is the obvious thing to do - * does not work as it gets caught up with `#include_next <stdlib.h>` - * not existing... - */ + if !cpp_compiler.contains("clang") { + command = command.add_extra_flag("-flax-vector-conversions"); + } + + let mut cpp_compiler = command.into_cpp_compilation(); + if config.target.contains("aarch64_be") { let Some(ref cxx_toolchain_dir) = config.cxx_toolchain_dir else { panic!( @@ -38,38 +32,20 @@ pub fn compile_c_arm(config: &ProcessedCli, intrinsics_name_list: &[String]) -> ) }; - let linker = if let Some(ref linker) = config.linker { - linker.to_owned() - } else { - format!("{cxx_toolchain_dir}/bin/aarch64_be-none-linux-gnu-g++") - }; - - trace!("using linker: {linker}"); - - command = command.set_linker(linker).set_include_paths(vec![ - "/include", - "/aarch64_be-none-linux-gnu/include", - "/aarch64_be-none-linux-gnu/include/c++/14.3.1", - "/aarch64_be-none-linux-gnu/include/c++/14.3.1/aarch64_be-none-linux-gnu", - "/aarch64_be-none-linux-gnu/include/c++/14.3.1/backward", - "/aarch64_be-none-linux-gnu/libc/usr/include", + cpp_compiler.command_mut().args([ + &format!("--sysroot={cxx_toolchain_dir}/aarch64_be-none-linux-gnu/libc"), + "--include-directory", + &format!("{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/include/c++/14.3.1"), + "--include-directory", + &format!("{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/include/c++/14.3.1/aarch64_be-none-linux-gnu"), + "-L", + &format!("{cxx_toolchain_dir}/lib/gcc/aarch64_be-none-linux-gnu/14.3.1"), + "-L", + &format!("{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/libc/usr/lib"), + "-B", + &format!("{cxx_toolchain_dir}/lib/gcc/aarch64_be-none-linux-gnu/14.3.1"), ]); } - if !cpp_compiler.contains("clang") { - command = command.add_extra_flag("-flax-vector-conversions"); - } - - let compiler_commands = intrinsics_name_list - .iter() - .map(|intrinsic_name| { - command - .clone() - .set_input_name(intrinsic_name) - .set_output_name(intrinsic_name) - .make_string() - }) - .collect::<Vec<_>>(); - - compile_c_programs(&compiler_commands) + Some(cpp_compiler) } diff --git a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs index a2535dc6a7a..18530e7e6bd 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs @@ -7,6 +7,7 @@ mod types; use crate::common::SupportedArchitectureTest; use crate::common::cli::ProcessedCli; use crate::common::compare::compare_outputs; +use crate::common::gen_c::compile_c_programs; use crate::common::gen_rust::compile_rust_programs; use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition}; use crate::common::intrinsic_helpers::TypeKind; @@ -66,7 +67,8 @@ impl SupportedArchitectureTest for ArmArchitectureTest { &[POLY128_OSTREAM_DEF], ); - compile::compile_c_arm(&self.cli_options, intrinsics_name_list.as_slice()) + let pipeline = compile::build_cpp_compilation(&self.cli_options).unwrap(); + compile_c_programs(&pipeline, &intrinsics_name_list) } fn build_rust_file(&self) -> bool { diff --git a/library/stdarch/crates/intrinsic-test/src/common/compile_c.rs b/library/stdarch/crates/intrinsic-test/src/common/compile_c.rs index aebb7b111e2..8e2eb8e0f40 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/compile_c.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/compile_c.rs @@ -5,11 +5,7 @@ pub struct CompilationCommandBuilder { cxx_toolchain_dir: Option<String>, arch_flags: Vec<String>, optimization: String, - include_paths: Vec<String>, project_root: Option<String>, - output: String, - input: String, - linker: Option<String>, extra_flags: Vec<String>, } @@ -21,11 +17,7 @@ impl CompilationCommandBuilder { 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(), } } @@ -57,37 +49,12 @@ impl CompilationCommandBuilder { 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<String> = flags.into_iter().map(|f| f.to_string()).collect(); self.extra_flags.append(&mut flags); @@ -100,55 +67,56 @@ impl CompilationCommandBuilder { } impl CompilationCommandBuilder { - pub fn make_string(self) -> String { - let arch_flags = self.arch_flags.join("+"); + 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()); - let project_root = self.project_root.unwrap_or_default(); - 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(); + 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 { - command = command + " --target=" + target; + cpp_compiler.arg(format!("--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::<Vec<_>>() - .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 + 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 run(&self, inputs: &[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() } } diff --git a/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs b/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs index 1cfb66c39b9..84167f2f4ae 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs @@ -1,7 +1,8 @@ use itertools::Itertools; use rayon::prelude::*; use std::collections::BTreeMap; -use std::process::Command; + +use crate::common::compile_c::CppCompilation; use super::argument::Argument; use super::indentation::Indentation; @@ -62,29 +63,30 @@ int main(int argc, char **argv) {{ ) } -pub fn compile_c_programs(compiler_commands: &[String]) -> bool { - compiler_commands +pub fn compile_c_programs(pipeline: &CppCompilation, intrinsics: &[String]) -> bool { + intrinsics .par_iter() - .map(|compiler_command| { - let output = Command::new("sh").arg("-c").arg(compiler_command).output(); - if let Ok(output) = output { - if output.status.success() { - true - } else { - error!( - "Failed to compile code for intrinsics: \n\nstdout:\n{}\n\nstderr:\n{}", + .map( + |intrinsic| match pipeline.run(&[format!("{intrinsic}.cpp")], intrinsic) { + Ok(output) if output.status.success() => Ok(()), + Ok(output) => { + let msg = format!( + "Failed to compile code for intrinsic `{intrinsic}`: \n\nstdout:\n{}\n\nstderr:\n{}", std::str::from_utf8(&output.stdout).unwrap_or(""), std::str::from_utf8(&output.stderr).unwrap_or("") ); - false + error!("{msg}"); + + Err(msg) } - } else { - error!("Command failed: {output:#?}"); - false - } - }) - .find_any(|x| !x) - .is_none() + Err(e) => { + error!("command for `{intrinsic}` failed with IO error: {e:?}"); + Err(e.to_string()) + } + }, + ) + .collect::<Result<(), String>>() + .is_ok() } // Creates directory structure and file path mappings |
