Auto merge of #43907 - euclio:command, r=alexcrichton
Use std::process::Command throughout compile-test Resubmission of #43798. Fixes #43762. r? @alexcrichton
This commit is contained in:
commit
a125ec918f
3 changed files with 242 additions and 453 deletions
|
|
@ -39,7 +39,6 @@ use util::logv;
|
|||
|
||||
use self::header::EarlyProps;
|
||||
|
||||
pub mod procsrv;
|
||||
pub mod util;
|
||||
mod json;
|
||||
pub mod header;
|
||||
|
|
|
|||
|
|
@ -1,134 +0,0 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::io::prelude::*;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Child, Command, ExitStatus, Output, Stdio};
|
||||
|
||||
/// Get the name of the environment variable that holds dynamic library
|
||||
/// locations
|
||||
pub fn dylib_env_var() -> &'static str {
|
||||
if cfg!(windows) {
|
||||
"PATH"
|
||||
} else if cfg!(target_os = "macos") {
|
||||
"DYLD_LIBRARY_PATH"
|
||||
} else if cfg!(target_os = "haiku") {
|
||||
"LIBRARY_PATH"
|
||||
} else {
|
||||
"LD_LIBRARY_PATH"
|
||||
}
|
||||
}
|
||||
|
||||
/// Add `lib_path` and `aux_path` (if it is `Some`) to the dynamic library
|
||||
/// env var
|
||||
fn add_target_env(cmd: &mut Command, lib_path: &str, aux_path: Option<&str>) {
|
||||
// Need to be sure to put both the lib_path and the aux path in the dylib
|
||||
// search path for the child.
|
||||
let var = dylib_env_var();
|
||||
let mut path = env::split_paths(&env::var_os(var).unwrap_or(OsString::new()))
|
||||
.collect::<Vec<_>>();
|
||||
if let Some(p) = aux_path {
|
||||
path.insert(0, PathBuf::from(p))
|
||||
}
|
||||
path.insert(0, PathBuf::from(lib_path));
|
||||
|
||||
// Add the new dylib search path var
|
||||
let newpath = env::join_paths(&path).unwrap();
|
||||
cmd.env(var, newpath);
|
||||
}
|
||||
|
||||
/// Represents exit status, stdout and stderr of a completed process
|
||||
pub struct Result {
|
||||
pub status: ExitStatus,
|
||||
pub out: String,
|
||||
pub err: String,
|
||||
}
|
||||
|
||||
/// Runs a test program
|
||||
///
|
||||
/// # Params
|
||||
/// - `lib_path` Path to search for required library
|
||||
/// - `prog` command to run
|
||||
/// - `aux_path` Optional extra path to search for required
|
||||
/// auxiliary libraries
|
||||
/// - `args` List of arguments to pass to `prog`
|
||||
/// - `env` List of environment variables to set, `.0` is variable name,
|
||||
/// `.1` is value
|
||||
/// - `input` String to be fed as stdin
|
||||
/// - `current_dir` Optional working dir to run command in
|
||||
///
|
||||
pub fn run(lib_path: &str,
|
||||
prog: &str,
|
||||
aux_path: Option<&str>,
|
||||
args: &[String],
|
||||
env: Vec<(String, String)>,
|
||||
input: Option<String>,
|
||||
current_dir: Option<String>)
|
||||
-> io::Result<Result> {
|
||||
|
||||
let mut cmd = Command::new(prog);
|
||||
cmd.args(args)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.stdin(Stdio::piped());
|
||||
|
||||
add_target_env(&mut cmd, lib_path, aux_path);
|
||||
for (key, val) in env {
|
||||
cmd.env(&key, &val);
|
||||
}
|
||||
if let Some(cwd) = current_dir {
|
||||
cmd.current_dir(cwd);
|
||||
}
|
||||
|
||||
let mut process = cmd.spawn()?;
|
||||
if let Some(input) = input {
|
||||
process.stdin.as_mut().unwrap().write_all(input.as_bytes()).unwrap();
|
||||
}
|
||||
let Output { status, stdout, stderr } = process.wait_with_output().unwrap();
|
||||
|
||||
Ok(Result {
|
||||
status,
|
||||
out: String::from_utf8(stdout).unwrap(),
|
||||
err: String::from_utf8(stderr).unwrap(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Same as `run`, but return process rather than waiting on completion
|
||||
pub fn run_background(lib_path: &str,
|
||||
prog: &str,
|
||||
aux_path: Option<&str>,
|
||||
args: &[String],
|
||||
env: Vec<(String, String)>,
|
||||
input: Option<String>,
|
||||
current_dir: Option<String>)
|
||||
-> io::Result<Child> {
|
||||
|
||||
let mut cmd = Command::new(prog);
|
||||
cmd.args(args)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped());
|
||||
add_target_env(&mut cmd, lib_path, aux_path);
|
||||
for (key, val) in env {
|
||||
cmd.env(&key, &val);
|
||||
}
|
||||
if let Some(cwd) = current_dir {
|
||||
cmd.current_dir(cwd);
|
||||
}
|
||||
|
||||
let mut process = cmd.spawn()?;
|
||||
if let Some(input) = input {
|
||||
process.stdin.as_mut().unwrap().write_all(input.as_bytes()).unwrap();
|
||||
}
|
||||
|
||||
Ok(process)
|
||||
}
|
||||
|
|
@ -17,22 +17,35 @@ use errors::{self, ErrorKind, Error};
|
|||
use filetime::FileTime;
|
||||
use json;
|
||||
use header::TestProps;
|
||||
use procsrv;
|
||||
use test::TestPaths;
|
||||
use util::logv;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::{self, File, create_dir_all};
|
||||
use std::io::prelude::*;
|
||||
use std::io::{self, BufReader};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, Output, ExitStatus};
|
||||
use std::process::{Command, Output, ExitStatus, Stdio};
|
||||
use std::str;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use extract_gdb_version;
|
||||
|
||||
/// The name of the environment variable that holds dynamic library locations.
|
||||
pub fn dylib_env_var() -> &'static str {
|
||||
if cfg!(windows) {
|
||||
"PATH"
|
||||
} else if cfg!(target_os = "macos") {
|
||||
"DYLD_LIBRARY_PATH"
|
||||
} else if cfg!(target_os = "haiku") {
|
||||
"LIBRARY_PATH"
|
||||
} else {
|
||||
"LD_LIBRARY_PATH"
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(config: Config, testpaths: &TestPaths) {
|
||||
match &*config.target {
|
||||
|
||||
|
|
@ -325,37 +338,23 @@ impl<'test> TestCx<'test> {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_source(&self,
|
||||
src: String,
|
||||
pretty_type: &str)
|
||||
-> ProcRes {
|
||||
fn print_source(&self, src: String, pretty_type: &str) -> ProcRes {
|
||||
let aux_dir = self.aux_output_dir_name();
|
||||
self.compose_and_run(self.make_pp_args(pretty_type.to_owned()),
|
||||
self.props.exec_env.clone(),
|
||||
|
||||
let mut rustc = Command::new(&self.config.rustc_path);
|
||||
rustc.arg("-")
|
||||
.arg("-Zunstable-options")
|
||||
.args(&["--unpretty", &pretty_type])
|
||||
.args(&["--target", &self.config.target])
|
||||
.arg("-L").arg(&aux_dir)
|
||||
.args(self.split_maybe_args(&self.config.target_rustcflags))
|
||||
.args(&self.props.compile_flags)
|
||||
.envs(self.props.exec_env.clone());
|
||||
|
||||
self.compose_and_run(rustc,
|
||||
self.config.compile_lib_path.to_str().unwrap(),
|
||||
Some(aux_dir.to_str().unwrap()),
|
||||
Some(src),
|
||||
None)
|
||||
}
|
||||
|
||||
fn make_pp_args(&self,
|
||||
pretty_type: String)
|
||||
-> ProcArgs {
|
||||
let aux_dir = self.aux_output_dir_name();
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let mut args = vec!["-".to_owned(),
|
||||
"-Zunstable-options".to_owned(),
|
||||
"--unpretty".to_owned(),
|
||||
pretty_type,
|
||||
format!("--target={}", self.config.target),
|
||||
"-L".to_owned(),
|
||||
aux_dir.to_str().unwrap().to_owned()];
|
||||
args.extend(self.split_maybe_args(&self.config.target_rustcflags));
|
||||
args.extend(self.props.compile_flags.iter().cloned());
|
||||
ProcArgs {
|
||||
prog: self.config.rustc_path.to_str().unwrap().to_owned(),
|
||||
args,
|
||||
}
|
||||
Some(src))
|
||||
}
|
||||
|
||||
fn compare_source(&self,
|
||||
|
|
@ -379,45 +378,35 @@ actual:\n\
|
|||
}
|
||||
|
||||
fn typecheck_source(&self, src: String) -> ProcRes {
|
||||
let args = self.make_typecheck_args();
|
||||
self.compose_and_run_compiler(args, Some(src))
|
||||
}
|
||||
let mut rustc = Command::new(&self.config.rustc_path);
|
||||
|
||||
let out_dir = self.output_base_name().with_extension("pretty-out");
|
||||
let _ = fs::remove_dir_all(&out_dir);
|
||||
create_dir_all(&out_dir).unwrap();
|
||||
|
||||
fn make_typecheck_args(&self) -> ProcArgs {
|
||||
let aux_dir = self.aux_output_dir_name();
|
||||
let target = if self.props.force_host {
|
||||
&*self.config.host
|
||||
} else {
|
||||
&*self.config.target
|
||||
};
|
||||
|
||||
let out_dir = self.output_base_name().with_extension("pretty-out");
|
||||
let _ = fs::remove_dir_all(&out_dir);
|
||||
create_dir_all(&out_dir).unwrap();
|
||||
let aux_dir = self.aux_output_dir_name();
|
||||
|
||||
rustc.arg("-")
|
||||
.arg("-Zno-trans")
|
||||
.arg("--out-dir").arg(&out_dir)
|
||||
.arg(&format!("--target={}", target))
|
||||
.arg("-L").arg(&self.config.build_base)
|
||||
.arg("-L").arg(aux_dir);
|
||||
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let mut args = vec!["-".to_owned(),
|
||||
"-Zno-trans".to_owned(),
|
||||
"--out-dir".to_owned(),
|
||||
out_dir.to_str().unwrap().to_owned(),
|
||||
format!("--target={}", target),
|
||||
"-L".to_owned(),
|
||||
self.config.build_base.to_str().unwrap().to_owned(),
|
||||
"-L".to_owned(),
|
||||
aux_dir.to_str().unwrap().to_owned()];
|
||||
if let Some(revision) = self.revision {
|
||||
args.extend(vec![
|
||||
"--cfg".to_string(),
|
||||
revision.to_string(),
|
||||
]);
|
||||
}
|
||||
args.extend(self.split_maybe_args(&self.config.target_rustcflags));
|
||||
args.extend(self.props.compile_flags.iter().cloned());
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
ProcArgs {
|
||||
prog: self.config.rustc_path.to_str().unwrap().to_owned(),
|
||||
args,
|
||||
rustc.args(&["--cfg", revision]);
|
||||
}
|
||||
|
||||
rustc.args(self.split_maybe_args(&self.config.target_rustcflags));
|
||||
rustc.args(&self.props.compile_flags);
|
||||
|
||||
self.compose_and_run_compiler(rustc, Some(src))
|
||||
}
|
||||
|
||||
fn run_debuginfo_gdb_test(&self) {
|
||||
|
|
@ -500,32 +489,19 @@ actual:\n\
|
|||
debug!("script_str = {}", script_str);
|
||||
self.dump_output_file(&script_str, "debugger.script");
|
||||
|
||||
let adb_path = &self.config.adb_path;
|
||||
|
||||
procsrv::run("",
|
||||
&self.config.adb_path,
|
||||
None,
|
||||
&[
|
||||
"push".to_owned(),
|
||||
exe_file.to_str().unwrap().to_owned(),
|
||||
self.config.adb_test_dir.clone()
|
||||
],
|
||||
Vec::new(),
|
||||
None,
|
||||
None)
|
||||
.expect(&format!("failed to exec `{:?}`", self.config.adb_path));
|
||||
Command::new(adb_path)
|
||||
.arg("push")
|
||||
.arg(&exe_file)
|
||||
.arg(&self.config.adb_test_dir)
|
||||
.status()
|
||||
.expect(&format!("failed to exec `{:?}`", adb_path));
|
||||
|
||||
procsrv::run("",
|
||||
&self.config.adb_path,
|
||||
None,
|
||||
&[
|
||||
"forward".to_owned(),
|
||||
"tcp:5039".to_owned(),
|
||||
"tcp:5039".to_owned()
|
||||
],
|
||||
Vec::new(),
|
||||
None,
|
||||
None)
|
||||
.expect(&format!("failed to exec `{:?}`", self.config.adb_path));
|
||||
Command::new(adb_path)
|
||||
.args(&["forward", "tcp:5039", "tcp:5039"])
|
||||
.status()
|
||||
.expect(&format!("failed to exec `{:?}`", adb_path));
|
||||
|
||||
let adb_arg = format!("export LD_LIBRARY_PATH={}; \
|
||||
gdbserver{} :5039 {}/{}",
|
||||
|
|
@ -537,23 +513,17 @@ actual:\n\
|
|||
.unwrap());
|
||||
|
||||
debug!("adb arg: {}", adb_arg);
|
||||
let mut process = procsrv::run_background("",
|
||||
&self.config.adb_path
|
||||
,
|
||||
None,
|
||||
&[
|
||||
"shell".to_owned(),
|
||||
adb_arg.clone()
|
||||
],
|
||||
Vec::new(),
|
||||
None,
|
||||
None)
|
||||
.expect(&format!("failed to exec `{:?}`", self.config.adb_path));
|
||||
let mut adb = Command::new(adb_path)
|
||||
.args(&["shell", &adb_arg])
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::inherit())
|
||||
.spawn()
|
||||
.expect(&format!("failed to exec `{:?}`", adb_path));
|
||||
|
||||
// Wait for the gdbserver to print out "Listening on port ..."
|
||||
// at which point we know that it's started and then we can
|
||||
// execute the debugger below.
|
||||
let mut stdout = BufReader::new(process.stdout.take().unwrap());
|
||||
let mut stdout = BufReader::new(adb.stdout.take().unwrap());
|
||||
let mut line = String::new();
|
||||
loop {
|
||||
line.truncate(0);
|
||||
|
|
@ -574,33 +544,29 @@ actual:\n\
|
|||
|
||||
let mut gdb_path = tool_path;
|
||||
gdb_path.push_str("/bin/gdb");
|
||||
let procsrv::Result {
|
||||
out,
|
||||
err,
|
||||
status
|
||||
} = procsrv::run("",
|
||||
&gdb_path,
|
||||
None,
|
||||
&debugger_opts,
|
||||
Vec::new(),
|
||||
None,
|
||||
None)
|
||||
let Output {
|
||||
status,
|
||||
stdout,
|
||||
stderr
|
||||
} = Command::new(&gdb_path)
|
||||
.args(&debugger_opts)
|
||||
.output()
|
||||
.expect(&format!("failed to exec `{:?}`", gdb_path));
|
||||
let cmdline = {
|
||||
let cmdline = self.make_cmdline("",
|
||||
&format!("{}-gdb", self.config.target),
|
||||
&debugger_opts);
|
||||
let mut gdb = Command::new(&format!("{}-gdb", self.config.target));
|
||||
gdb.args(&debugger_opts);
|
||||
let cmdline = self.make_cmdline(&gdb, "");
|
||||
logv(self.config, format!("executing {}", cmdline));
|
||||
cmdline
|
||||
};
|
||||
|
||||
debugger_run_result = ProcRes {
|
||||
status,
|
||||
stdout: out,
|
||||
stderr: err,
|
||||
stdout: String::from_utf8(stdout).unwrap(),
|
||||
stderr: String::from_utf8(stderr).unwrap(),
|
||||
cmdline,
|
||||
};
|
||||
if process.kill().is_err() {
|
||||
if adb.kill().is_err() {
|
||||
println!("Adb process is already finished.");
|
||||
}
|
||||
}
|
||||
|
|
@ -679,19 +645,14 @@ actual:\n\
|
|||
"-nx".to_owned(),
|
||||
format!("-command={}", debugger_script.to_str().unwrap())];
|
||||
|
||||
let proc_args = ProcArgs {
|
||||
prog: self.config.gdb.as_ref().unwrap().to_owned(),
|
||||
args: debugger_opts,
|
||||
};
|
||||
|
||||
let environment = vec![("PYTHONPATH".to_owned(), rust_pp_module_abs_path)];
|
||||
let mut gdb = Command::new(self.config.gdb.as_ref().unwrap());
|
||||
gdb.args(&debugger_opts)
|
||||
.env("PYTHONPATH", rust_pp_module_abs_path);
|
||||
|
||||
debugger_run_result =
|
||||
self.compose_and_run(proc_args,
|
||||
environment,
|
||||
self.compose_and_run(gdb,
|
||||
self.config.run_lib_path.to_str().unwrap(),
|
||||
None,
|
||||
None,
|
||||
None);
|
||||
}
|
||||
}
|
||||
|
|
@ -1154,10 +1115,11 @@ actual:\n\
|
|||
}
|
||||
|
||||
fn compile_test(&self) -> ProcRes {
|
||||
let aux_dir = self.aux_output_dir_name();
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let mut extra_args = vec!["-L".to_owned(),
|
||||
aux_dir.to_str().unwrap().to_owned()];
|
||||
let mut rustc = self.make_compile_args(
|
||||
&self.testpaths.file, TargetLocation::ThisFile(self.make_exe_name()));
|
||||
|
||||
rustc.arg("-L").arg(&self.aux_output_dir_name());
|
||||
|
||||
match self.config.mode {
|
||||
CompileFail | Ui => {
|
||||
// compile-fail and ui tests tend to have tons of unused code as
|
||||
|
|
@ -1165,15 +1127,12 @@ actual:\n\
|
|||
// want to actually assert warnings about all this code. Instead
|
||||
// let's just ignore unused code warnings by defaults and tests
|
||||
// can turn it back on if needed.
|
||||
extra_args.push("-A".to_owned());
|
||||
extra_args.push("unused".to_owned());
|
||||
rustc.args(&["-A", "unused"]);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let args = self.make_compile_args(extra_args,
|
||||
&self.testpaths.file,
|
||||
TargetLocation::ThisFile(self.make_exe_name()));
|
||||
self.compose_and_run_compiler(args, None)
|
||||
|
||||
self.compose_and_run_compiler(rustc, None)
|
||||
}
|
||||
|
||||
fn document(&self, out_dir: &Path) -> ProcRes {
|
||||
|
|
@ -1197,22 +1156,20 @@ actual:\n\
|
|||
}
|
||||
|
||||
let aux_dir = self.aux_output_dir_name();
|
||||
let mut args = vec!["-L".to_owned(),
|
||||
aux_dir.to_str().unwrap().to_owned(),
|
||||
"-o".to_owned(),
|
||||
out_dir.to_str().unwrap().to_owned(),
|
||||
self.testpaths.file.to_str().unwrap().to_owned()];
|
||||
args.extend(self.props.compile_flags.iter().cloned());
|
||||
let args = ProcArgs {
|
||||
prog: self.config.rustdoc_path
|
||||
.as_ref().expect("--rustdoc-path passed").to_str().unwrap().to_owned(),
|
||||
args,
|
||||
};
|
||||
self.compose_and_run_compiler(args, None)
|
||||
|
||||
let rustdoc_path = self.config.rustdoc_path.as_ref().expect("--rustdoc-path passed");
|
||||
let mut rustdoc = Command::new(rustdoc_path);
|
||||
|
||||
rustdoc.arg("-L").arg(aux_dir)
|
||||
.arg("-o").arg(out_dir)
|
||||
.arg(&self.testpaths.file)
|
||||
.args(&self.props.compile_flags);
|
||||
|
||||
self.compose_and_run_compiler(rustdoc, None)
|
||||
}
|
||||
|
||||
fn exec_compiled_test(&self) -> ProcRes {
|
||||
let env = self.props.exec_env.clone();
|
||||
let env = &self.props.exec_env;
|
||||
|
||||
match &*self.config.target {
|
||||
// This is pretty similar to below, we're transforming:
|
||||
|
|
@ -1230,41 +1187,39 @@ actual:\n\
|
|||
// the process) and then report back the same result.
|
||||
_ if self.config.remote_test_client.is_some() => {
|
||||
let aux_dir = self.aux_output_dir_name();
|
||||
let mut args = self.make_run_args();
|
||||
let mut program = args.prog.clone();
|
||||
let ProcArgs { mut prog, args } = self.make_run_args();
|
||||
if let Ok(entries) = aux_dir.read_dir() {
|
||||
for entry in entries {
|
||||
let entry = entry.unwrap();
|
||||
if !entry.path().is_file() {
|
||||
continue
|
||||
}
|
||||
program.push_str(":");
|
||||
program.push_str(entry.path().to_str().unwrap());
|
||||
prog.push_str(":");
|
||||
prog.push_str(entry.path().to_str().unwrap());
|
||||
}
|
||||
}
|
||||
args.args.insert(0, program);
|
||||
args.args.insert(0, "run".to_string());
|
||||
args.prog = self.config.remote_test_client.clone().unwrap()
|
||||
.into_os_string().into_string().unwrap();
|
||||
self.compose_and_run(args,
|
||||
env,
|
||||
let mut test_client = Command::new(
|
||||
self.config.remote_test_client.as_ref().unwrap());
|
||||
test_client
|
||||
.args(&["run", &prog])
|
||||
.args(args)
|
||||
.envs(env.clone());
|
||||
self.compose_and_run(test_client,
|
||||
self.config.run_lib_path.to_str().unwrap(),
|
||||
Some(aux_dir.to_str().unwrap()),
|
||||
None,
|
||||
None)
|
||||
}
|
||||
_ => {
|
||||
let aux_dir = self.aux_output_dir_name();
|
||||
let working_dir =
|
||||
Some(self.output_base_name()
|
||||
.parent().unwrap()
|
||||
.to_str().unwrap().to_owned());
|
||||
self.compose_and_run(self.make_run_args(),
|
||||
env,
|
||||
let ProcArgs { prog, args } = self.make_run_args();
|
||||
let mut program = Command::new(&prog);
|
||||
program.args(args)
|
||||
.current_dir(&self.output_base_name().parent().unwrap())
|
||||
.envs(env.clone());
|
||||
self.compose_and_run(program,
|
||||
self.config.run_lib_path.to_str().unwrap(),
|
||||
Some(aux_dir.to_str().unwrap()),
|
||||
None,
|
||||
working_dir)
|
||||
None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1293,39 +1248,18 @@ actual:\n\
|
|||
}
|
||||
}
|
||||
|
||||
fn compose_and_run_compiler(&self, args: ProcArgs, input: Option<String>) -> ProcRes {
|
||||
fn compose_and_run_compiler(&self, mut rustc: Command, input: Option<String>) -> ProcRes {
|
||||
if !self.props.aux_builds.is_empty() {
|
||||
create_dir_all(&self.aux_output_dir_name()).unwrap();
|
||||
}
|
||||
|
||||
let aux_dir = self.aux_output_dir_name();
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let extra_link_args = vec!["-L".to_owned(),
|
||||
aux_dir.to_str().unwrap().to_owned()];
|
||||
|
||||
for rel_ab in &self.props.aux_builds {
|
||||
let aux_testpaths = self.compute_aux_test_paths(rel_ab);
|
||||
let aux_props = self.props.from_aux_file(&aux_testpaths.file,
|
||||
self.revision,
|
||||
self.config);
|
||||
let mut crate_type = if aux_props.no_prefer_dynamic {
|
||||
Vec::new()
|
||||
} else if (self.config.target.contains("musl") && !aux_props.force_host) ||
|
||||
self.config.target.contains("emscripten") {
|
||||
// We primarily compile all auxiliary libraries as dynamic libraries
|
||||
// to avoid code size bloat and large binaries as much as possible
|
||||
// for the test suite (otherwise including libstd statically in all
|
||||
// executables takes up quite a bit of space).
|
||||
//
|
||||
// For targets like MUSL or Emscripten, however, there is no support for
|
||||
// dynamic libraries so we just go back to building a normal library. Note,
|
||||
// however, that for MUSL if the library is built with `force_host` then
|
||||
// it's ok to be a dylib as the host should always support dylibs.
|
||||
vec!["--crate-type=lib".to_owned()]
|
||||
} else {
|
||||
vec!["--crate-type=dylib".to_owned()]
|
||||
};
|
||||
crate_type.extend(extra_link_args.clone());
|
||||
let aux_output = {
|
||||
let f = self.make_lib_name(&self.testpaths.file);
|
||||
let parent = f.parent().unwrap();
|
||||
|
|
@ -1337,12 +1271,35 @@ actual:\n\
|
|||
testpaths: &aux_testpaths,
|
||||
revision: self.revision
|
||||
};
|
||||
let aux_args = aux_cx.make_compile_args(crate_type, &aux_testpaths.file, aux_output);
|
||||
let auxres = aux_cx.compose_and_run(aux_args,
|
||||
Vec::new(),
|
||||
let mut aux_rustc = aux_cx.make_compile_args(&aux_testpaths.file, aux_output);
|
||||
|
||||
let crate_type = if aux_props.no_prefer_dynamic {
|
||||
None
|
||||
} else if (self.config.target.contains("musl") && !aux_props.force_host) ||
|
||||
self.config.target.contains("emscripten") {
|
||||
// We primarily compile all auxiliary libraries as dynamic libraries
|
||||
// to avoid code size bloat and large binaries as much as possible
|
||||
// for the test suite (otherwise including libstd statically in all
|
||||
// executables takes up quite a bit of space).
|
||||
//
|
||||
// For targets like MUSL or Emscripten, however, there is no support for
|
||||
// dynamic libraries so we just go back to building a normal library. Note,
|
||||
// however, that for MUSL if the library is built with `force_host` then
|
||||
// it's ok to be a dylib as the host should always support dylibs.
|
||||
Some("lib")
|
||||
} else {
|
||||
Some("dylib")
|
||||
};
|
||||
|
||||
if let Some(crate_type) = crate_type {
|
||||
aux_rustc.args(&["--crate-type", crate_type]);
|
||||
}
|
||||
|
||||
aux_rustc.arg("-L").arg(&aux_dir);
|
||||
|
||||
let auxres = aux_cx.compose_and_run(aux_rustc,
|
||||
aux_cx.config.compile_lib_path.to_str().unwrap(),
|
||||
Some(aux_dir.to_str().unwrap()),
|
||||
None,
|
||||
None);
|
||||
if !auxres.status.success() {
|
||||
self.fatal_proc_rec(
|
||||
|
|
@ -1352,40 +1309,65 @@ actual:\n\
|
|||
}
|
||||
}
|
||||
|
||||
self.compose_and_run(args,
|
||||
self.props.rustc_env.clone(),
|
||||
rustc.envs(self.props.rustc_env.clone());
|
||||
self.compose_and_run(rustc,
|
||||
self.config.compile_lib_path.to_str().unwrap(),
|
||||
Some(aux_dir.to_str().unwrap()),
|
||||
input,
|
||||
None)
|
||||
input)
|
||||
}
|
||||
|
||||
fn compose_and_run(&self,
|
||||
ProcArgs{ args, prog }: ProcArgs,
|
||||
procenv: Vec<(String, String)> ,
|
||||
mut command: Command,
|
||||
lib_path: &str,
|
||||
aux_path: Option<&str>,
|
||||
input: Option<String>,
|
||||
working_dir: Option<String>) -> ProcRes {
|
||||
self.program_output(lib_path, prog, aux_path, args, procenv, input, working_dir)
|
||||
}
|
||||
|
||||
fn make_compile_args(&self,
|
||||
extras: Vec<String> ,
|
||||
input_file: &Path,
|
||||
output_file: TargetLocation)
|
||||
-> ProcArgs
|
||||
{
|
||||
let target = if self.props.force_host {
|
||||
&*self.config.host
|
||||
} else {
|
||||
&*self.config.target
|
||||
input: Option<String>) -> ProcRes {
|
||||
let cmdline =
|
||||
{
|
||||
let cmdline = self.make_cmdline(&command, lib_path);
|
||||
logv(self.config, format!("executing {}", cmdline));
|
||||
cmdline
|
||||
};
|
||||
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let mut args = vec![input_file.to_str().unwrap().to_owned(),
|
||||
"-L".to_owned(),
|
||||
self.config.build_base.to_str().unwrap().to_owned()];
|
||||
command
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.stdin(Stdio::piped());
|
||||
|
||||
// Need to be sure to put both the lib_path and the aux path in the dylib
|
||||
// search path for the child.
|
||||
let mut path = env::split_paths(&env::var_os(dylib_env_var()).unwrap_or(OsString::new()))
|
||||
.collect::<Vec<_>>();
|
||||
if let Some(p) = aux_path {
|
||||
path.insert(0, PathBuf::from(p))
|
||||
}
|
||||
path.insert(0, PathBuf::from(lib_path));
|
||||
|
||||
// Add the new dylib search path var
|
||||
let newpath = env::join_paths(&path).unwrap();
|
||||
command.env(dylib_env_var(), newpath);
|
||||
|
||||
let mut child = command.spawn().expect(&format!("failed to exec `{:?}`", &command));
|
||||
if let Some(input) = input {
|
||||
child.stdin.as_mut().unwrap().write_all(input.as_bytes()).unwrap();
|
||||
}
|
||||
let Output { status, stdout, stderr } = child.wait_with_output().unwrap();
|
||||
|
||||
let result = ProcRes {
|
||||
status,
|
||||
stdout: String::from_utf8(stdout).unwrap(),
|
||||
stderr: String::from_utf8(stderr).unwrap(),
|
||||
cmdline,
|
||||
};
|
||||
|
||||
self.dump_output(&result.stdout, &result.stderr);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn make_compile_args(&self, input_file: &Path, output_file: TargetLocation) -> Command {
|
||||
let mut rustc = Command::new(&self.config.rustc_path);
|
||||
rustc.arg(input_file)
|
||||
.arg("-L").arg(&self.config.build_base);
|
||||
|
||||
// Optionally prevent default --target if specified in test compile-flags.
|
||||
let custom_target = self.props.compile_flags
|
||||
|
|
@ -1393,26 +1375,23 @@ actual:\n\
|
|||
.fold(false, |acc, x| acc || x.starts_with("--target"));
|
||||
|
||||
if !custom_target {
|
||||
args.extend(vec![
|
||||
format!("--target={}", target),
|
||||
]);
|
||||
let target = if self.props.force_host {
|
||||
&*self.config.host
|
||||
} else {
|
||||
&*self.config.target
|
||||
};
|
||||
|
||||
rustc.arg(&format!("--target={}", target));
|
||||
}
|
||||
|
||||
if let Some(revision) = self.revision {
|
||||
args.extend(vec![
|
||||
"--cfg".to_string(),
|
||||
revision.to_string(),
|
||||
]);
|
||||
rustc.args(&["--cfg", revision]);
|
||||
}
|
||||
|
||||
if let Some(ref incremental_dir) = self.props.incremental_dir {
|
||||
args.extend(vec![
|
||||
"-Z".to_string(),
|
||||
format!("incremental={}", incremental_dir.display()),
|
||||
]);
|
||||
rustc.args(&["-Z", &format!("incremental={}", incremental_dir.display())]);
|
||||
}
|
||||
|
||||
|
||||
match self.config.mode {
|
||||
CompileFail |
|
||||
ParseFail |
|
||||
|
|
@ -1421,19 +1400,14 @@ actual:\n\
|
|||
// fashion, then you want JSON mode. Old-skool error
|
||||
// patterns still match the raw compiler output.
|
||||
if self.props.error_patterns.is_empty() {
|
||||
args.extend(["--error-format",
|
||||
"json"]
|
||||
.iter()
|
||||
.map(|s| s.to_string()));
|
||||
rustc.args(&["--error-format", "json"]);
|
||||
}
|
||||
}
|
||||
MirOpt => {
|
||||
args.extend(["-Zdump-mir=all",
|
||||
"-Zmir-opt-level=3",
|
||||
"-Zdump-mir-exclude-pass-number"]
|
||||
.iter()
|
||||
.map(|s| s.to_string()));
|
||||
|
||||
rustc.args(&[
|
||||
"-Zdump-mir=all",
|
||||
"-Zmir-opt-level=3",
|
||||
"-Zdump-mir-exclude-pass-number"]);
|
||||
|
||||
let mir_dump_dir = self.get_mir_dump_dir();
|
||||
create_dir_all(mir_dump_dir.as_path()).unwrap();
|
||||
|
|
@ -1441,7 +1415,7 @@ actual:\n\
|
|||
dir_opt.push_str(mir_dump_dir.to_str().unwrap());
|
||||
debug!("dir_opt: {:?}", dir_opt);
|
||||
|
||||
args.push(dir_opt);
|
||||
rustc.arg(dir_opt);
|
||||
}
|
||||
RunPass |
|
||||
RunFail |
|
||||
|
|
@ -1458,32 +1432,28 @@ actual:\n\
|
|||
}
|
||||
}
|
||||
|
||||
args.extend_from_slice(&extras);
|
||||
if !self.props.no_prefer_dynamic {
|
||||
args.push("-C".to_owned());
|
||||
args.push("prefer-dynamic".to_owned());
|
||||
rustc.args(&["-C", "prefer-dynamic"]);
|
||||
}
|
||||
let path = match output_file {
|
||||
|
||||
match output_file {
|
||||
TargetLocation::ThisFile(path) => {
|
||||
args.push("-o".to_owned());
|
||||
path
|
||||
rustc.arg("-o").arg(path);
|
||||
}
|
||||
TargetLocation::ThisDirectory(path) => {
|
||||
args.push("--out-dir".to_owned());
|
||||
path
|
||||
rustc.arg("--out-dir").arg(path);
|
||||
}
|
||||
};
|
||||
args.push(path.to_str().unwrap().to_owned());
|
||||
}
|
||||
|
||||
if self.props.force_host {
|
||||
args.extend(self.split_maybe_args(&self.config.host_rustcflags));
|
||||
rustc.args(self.split_maybe_args(&self.config.host_rustcflags));
|
||||
} else {
|
||||
args.extend(self.split_maybe_args(&self.config.target_rustcflags));
|
||||
}
|
||||
args.extend(self.props.compile_flags.iter().cloned());
|
||||
ProcArgs {
|
||||
prog: self.config.rustc_path.to_str().unwrap().to_owned(),
|
||||
args,
|
||||
rustc.args(self.split_maybe_args(&self.config.target_rustcflags));
|
||||
}
|
||||
|
||||
rustc.args(&self.props.compile_flags);
|
||||
|
||||
rustc
|
||||
}
|
||||
|
||||
fn make_lib_name(&self, auxfile: &Path) -> PathBuf {
|
||||
|
|
@ -1554,50 +1524,12 @@ actual:\n\
|
|||
}
|
||||
}
|
||||
|
||||
fn program_output(&self,
|
||||
lib_path: &str,
|
||||
prog: String,
|
||||
aux_path: Option<&str>,
|
||||
args: Vec<String>,
|
||||
env: Vec<(String, String)>,
|
||||
input: Option<String>,
|
||||
working_dir: Option<String>)
|
||||
-> ProcRes {
|
||||
let cmdline =
|
||||
{
|
||||
let cmdline = self.make_cmdline(lib_path,
|
||||
&prog,
|
||||
&args);
|
||||
logv(self.config, format!("executing {}", cmdline));
|
||||
cmdline
|
||||
};
|
||||
|
||||
let procsrv::Result {
|
||||
out,
|
||||
err,
|
||||
status
|
||||
} = procsrv::run(lib_path,
|
||||
&prog,
|
||||
aux_path,
|
||||
&args,
|
||||
env,
|
||||
input,
|
||||
working_dir).expect(&format!("failed to exec `{}`", prog));
|
||||
self.dump_output(&out, &err);
|
||||
ProcRes {
|
||||
status,
|
||||
stdout: out,
|
||||
stderr: err,
|
||||
cmdline,
|
||||
}
|
||||
}
|
||||
|
||||
fn make_cmdline(&self, libpath: &str, prog: &str, args: &[String]) -> String {
|
||||
fn make_cmdline(&self, command: &Command, libpath: &str) -> String {
|
||||
use util;
|
||||
|
||||
// Linux and mac don't require adjusting the library search path
|
||||
if cfg!(unix) {
|
||||
format!("{} {}", prog, args.join(" "))
|
||||
format!("{:?}", command)
|
||||
} else {
|
||||
// Build the LD_LIBRARY_PATH variable as it would be seen on the command line
|
||||
// for diagnostic purposes
|
||||
|
|
@ -1605,7 +1537,7 @@ actual:\n\
|
|||
format!("{}=\"{}\"", util::lib_path_env_var(), util::make_new_path(path))
|
||||
}
|
||||
|
||||
format!("{} {} {}", lib_path_cmd_prefix(libpath), prog, args.join(" "))
|
||||
format!("{} {:?}", lib_path_cmd_prefix(libpath), command)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1723,30 +1655,22 @@ actual:\n\
|
|||
|
||||
fn compile_test_and_save_ir(&self) -> ProcRes {
|
||||
let aux_dir = self.aux_output_dir_name();
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let mut link_args = vec!["-L".to_owned(),
|
||||
aux_dir.to_str().unwrap().to_owned()];
|
||||
let llvm_args = vec!["--emit=llvm-ir".to_owned(),];
|
||||
link_args.extend(llvm_args);
|
||||
let args = self.make_compile_args(link_args,
|
||||
&self.testpaths.file,
|
||||
TargetLocation::ThisDirectory(
|
||||
self.output_base_name().parent()
|
||||
.unwrap()
|
||||
.to_path_buf()));
|
||||
self.compose_and_run_compiler(args, None)
|
||||
|
||||
let output_file = TargetLocation::ThisDirectory(
|
||||
self.output_base_name().parent().unwrap().to_path_buf());
|
||||
let mut rustc = self.make_compile_args(&self.testpaths.file, output_file);
|
||||
rustc.arg("-L").arg(aux_dir)
|
||||
.arg("--emit=llvm-ir");
|
||||
|
||||
self.compose_and_run_compiler(rustc, None)
|
||||
}
|
||||
|
||||
fn check_ir_with_filecheck(&self) -> ProcRes {
|
||||
let irfile = self.output_base_name().with_extension("ll");
|
||||
let prog = self.config.llvm_filecheck.as_ref().unwrap();
|
||||
let proc_args = ProcArgs {
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
prog: prog.to_str().unwrap().to_owned(),
|
||||
args: vec![format!("-input-file={}", irfile.to_str().unwrap()),
|
||||
self.testpaths.file.to_str().unwrap().to_owned()]
|
||||
};
|
||||
self.compose_and_run(proc_args, Vec::new(), "", None, None, None)
|
||||
let mut filecheck = Command::new(self.config.llvm_filecheck.as_ref().unwrap());
|
||||
filecheck.arg("--input-file").arg(irfile)
|
||||
.arg(&self.testpaths.file);
|
||||
self.compose_and_run(filecheck, "", None, None)
|
||||
}
|
||||
|
||||
fn run_codegen_test(&self) {
|
||||
|
|
@ -2179,7 +2103,7 @@ actual:\n\
|
|||
.env("RUSTDOC",
|
||||
cwd.join(&self.config.rustdoc_path.as_ref().expect("--rustdoc-path passed")))
|
||||
.env("TMPDIR", &tmpdir)
|
||||
.env("LD_LIB_PATH_ENVVAR", procsrv::dylib_env_var())
|
||||
.env("LD_LIB_PATH_ENVVAR", dylib_env_var())
|
||||
.env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path))
|
||||
.env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path))
|
||||
.env("LLVM_COMPONENTS", &self.config.llvm_components)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue