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:
bors 2017-08-24 10:02:18 +00:00
commit a125ec918f
3 changed files with 242 additions and 453 deletions

View file

@ -39,7 +39,6 @@ use util::logv;
use self::header::EarlyProps;
pub mod procsrv;
pub mod util;
mod json;
pub mod header;

View file

@ -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)
}

View file

@ -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)