Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 25 additions & 13 deletions build_system/src/rust_tools.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use std::collections::HashMap;
use std::ffi::OsStr;
#[cfg(unix)]
use std::os::unix::process::CommandExt;
use std::path::PathBuf;

use crate::config::ConfigInfo;
use crate::utils::{
get_toolchain, run_command_with_output_and_env_no_err, rustc_toolchain_version_info,
rustc_version_info,
};
use crate::utils::{get_toolchain, rustc_toolchain_version_info, rustc_version_info};

fn args(command: &str) -> Result<Option<Vec<String>>, String> {
// We skip the binary and the "cargo"/"rustc" option.
Expand Down Expand Up @@ -97,6 +96,26 @@ impl RustcTools {
}
}

fn exec(input: &[&dyn AsRef<OsStr>], env: &HashMap<String, String>) -> Result<(), String> {
#[cfg(unix)]
{
// We use `exec` to call the `execvp` syscall instead of creating a new process where the
// command will be executed because very few signals can actually kill a current process,
// so if segmentation fault (SIGSEGV signal) happens and we raise to the current process,
// it will simply do nothing and we won't have the nice error message for the shell.
let error = crate::utils::get_command_inner(input, None, Some(env)).exec();
eprintln!("execvp syscall failed: {error:?}");
std::process::exit(1);
}
#[cfg(not(unix))]
{
if crate::utils::run_command_with_output_and_env_no_err(input, None, Some(env)).is_err() {
std::process::exit(1);
}
Ok(())
}
}

pub fn run_cargo() -> Result<(), String> {
let Some(mut tools) = RustcTools::new("cargo")? else { return Ok(()) };
let rustflags = tools.env.get("RUSTFLAGS").cloned().unwrap_or_default();
Expand All @@ -105,11 +124,7 @@ pub fn run_cargo() -> Result<(), String> {
for arg in &tools.args {
command.push(arg);
}
if run_command_with_output_and_env_no_err(&command, None, Some(&tools.env)).is_err() {
std::process::exit(1);
}

Ok(())
exec(&command, &tools.env)
}

pub fn run_rustc() -> Result<(), String> {
Expand All @@ -118,8 +133,5 @@ pub fn run_rustc() -> Result<(), String> {
for arg in &tools.args {
command.push(arg);
}
if run_command_with_output_and_env_no_err(&command, None, Some(&tools.env)).is_err() {
std::process::exit(1);
}
Ok(())
exec(&command, &tools.env)
}
13 changes: 2 additions & 11 deletions build_system/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
use std::collections::HashMap;
use std::ffi::OsStr;
#[cfg(unix)]
use std::ffi::c_int;
use std::fmt::Debug;
use std::fs;
#[cfg(unix)]
use std::os::unix::process::ExitStatusExt;
use std::path::{Path, PathBuf};
use std::process::{Command, ExitStatus, Output};

#[cfg(unix)]
unsafe extern "C" {
fn raise(signal: c_int) -> c_int;
}

fn exec_command(
input: &[&dyn AsRef<OsStr>],
cwd: Option<&Path>,
Expand All @@ -27,17 +20,14 @@ fn exec_command(
#[cfg(unix)]
{
if let Some(signal) = status.signal() {
unsafe {
raise(signal as _);
}
// In case the signal didn't kill the current process.
return Err(command_error(input, &cwd, format!("Process received signal {}", signal)));
}
}
Ok(status)
}

fn get_command_inner(
pub(crate) fn get_command_inner(
input: &[&dyn AsRef<OsStr>],
cwd: Option<&Path>,
env: Option<&HashMap<String, String>>,
Expand Down Expand Up @@ -136,6 +126,7 @@ pub fn run_command_with_output_and_env(
Ok(())
}

#[cfg(not(unix))]
pub fn run_command_with_output_and_env_no_err(
input: &[&dyn AsRef<OsStr>],
cwd: Option<&Path>,
Expand Down