rust/src/compiletest/runtest.rs

1791 lines
62 KiB
Rust
Raw Normal View History

// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
2012-12-10 23:44:02 +00:00
// 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.
2014-11-21 22:15:33 +00:00
use self::TargetLocation::*;
2012-12-10 23:44:02 +00:00
2014-04-16 04:56:39 +00:00
use common::Config;
use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
use common::{Codegen, DebugInfoLldb, DebugInfoGdb};
2012-12-28 16:50:27 +00:00
use errors;
use header::TestProps;
use header;
2012-12-28 16:50:27 +00:00
use procsrv;
use util::logv;
std: Add a new `env` module This is an implementation of [RFC 578][rfc] which adds a new `std::env` module to replace most of the functionality in the current `std::os` module. More details can be found in the RFC itself, but as a summary the following methods have all been deprecated: [rfc]: https://github.com/rust-lang/rfcs/pull/578 * `os::args_as_bytes` => `env::args` * `os::args` => `env::args` * `os::consts` => `env::consts` * `os::dll_filename` => no replacement, use `env::consts` directly * `os::page_size` => `env::page_size` * `os::make_absolute` => use `env::current_dir` + `join` instead * `os::getcwd` => `env::current_dir` * `os::change_dir` => `env::set_current_dir` * `os::homedir` => `env::home_dir` * `os::tmpdir` => `env::temp_dir` * `os::join_paths` => `env::join_paths` * `os::split_paths` => `env::split_paths` * `os::self_exe_name` => `env::current_exe` * `os::self_exe_path` => use `env::current_exe` + `pop` * `os::set_exit_status` => `env::set_exit_status` * `os::get_exit_status` => `env::get_exit_status` * `os::env` => `env::vars` * `os::env_as_bytes` => `env::vars` * `os::getenv` => `env::var` or `env::var_string` * `os::getenv_as_bytes` => `env::var` * `os::setenv` => `env::set_var` * `os::unsetenv` => `env::remove_var` Many function signatures have also been tweaked for various purposes, but the main changes were: * `Vec`-returning APIs now all return iterators instead * All APIs are now centered around `OsString` instead of `Vec<u8>` or `String`. There is currently on convenience API, `env::var_string`, which can be used to get the value of an environment variable as a unicode `String`. All old APIs are `#[deprecated]` in-place and will remain for some time to allow for migrations. The semantics of the APIs have been tweaked slightly with regard to dealing with invalid unicode (panic instead of replacement). The new `std::env` module is all contained within the `env` feature, so crates must add the following to access the new APIs: #![feature(env)] [breaking-change]
2015-01-27 20:20:58 +00:00
use std::env;
use std::ffi::OsStr;
use std::fmt;
use std::fs::{self, File};
use std::io::BufReader;
use std::io::prelude::*;
2014-12-30 18:51:18 +00:00
use std::iter::repeat;
use std::net::TcpStream;
use std::old_io::timer;
use std::path::{Path, PathBuf};
use std::process::{Command, Output, ExitStatus};
use std::str;
2014-08-01 01:03:20 +00:00
use std::time::Duration;
2014-02-14 01:49:11 +00:00
use test::MetricMap;
pub fn run(config: Config, testfile: &Path) {
match &*config.target {
"arm-linux-androideabi" | "aarch64-linux-android" => {
if !config.adb_device_status {
panic!("android device not available");
}
}
_=> { }
}
let mut _mm = MetricMap::new();
run_metrics(config, testfile, &mut _mm);
}
pub fn run_metrics(config: Config, testfile: &Path, mm: &mut MetricMap) {
if config.verbose {
// We're going to be dumping a lot of info. Start on a new line.
print!("\n\n");
}
debug!("running {:?}", testfile.display());
let props = header::load_props(&testfile);
debug!("loaded props");
2012-08-06 19:34:08 +00:00
match config.mode {
2014-04-16 04:56:39 +00:00
CompileFail => run_cfail_test(&config, &props, &testfile),
2015-02-11 22:09:30 +00:00
ParseFail => run_cfail_test(&config, &props, &testfile),
2014-04-16 04:56:39 +00:00
RunFail => run_rfail_test(&config, &props, &testfile),
RunPass => run_rpass_test(&config, &props, &testfile),
RunPassValgrind => run_valgrind_test(&config, &props, &testfile),
2014-04-16 04:56:39 +00:00
Pretty => run_pretty_test(&config, &props, &testfile),
DebugInfoGdb => run_debuginfo_gdb_test(&config, &props, &testfile),
DebugInfoLldb => run_debuginfo_lldb_test(&config, &props, &testfile),
Codegen => run_codegen_test(&config, &props, &testfile, mm),
}
}
fn get_output(props: &TestProps, proc_res: &ProcRes) -> String {
if props.check_stdout {
format!("{}{}", proc_res.stdout, proc_res.stderr)
} else {
proc_res.stderr.clone()
}
}
2014-04-16 04:56:39 +00:00
fn run_cfail_test(config: &Config, props: &TestProps, testfile: &Path) {
let proc_res = compile_test(config, props, testfile);
if proc_res.status.success() {
fatal_proc_rec(&format!("{} test compiled successfully!", config.mode)[..],
&proc_res);
}
check_correct_failure_status(&proc_res);
if proc_res.status.success() {
fatal("process did not return an error status");
}
let output_to_check = get_output(props, &proc_res);
let expected_errors = errors::load_errors(testfile);
if !expected_errors.is_empty() {
if !props.error_patterns.is_empty() {
fatal("both error pattern and expected errors specified");
}
check_expected_errors(expected_errors, testfile, &proc_res);
} else {
check_error_patterns(props, testfile, &output_to_check, &proc_res);
}
check_no_compiler_crash(&proc_res);
check_forbid_output(props, &output_to_check, &proc_res);
}
2014-04-16 04:56:39 +00:00
fn run_rfail_test(config: &Config, props: &TestProps, testfile: &Path) {
let proc_res = if !config.jit {
let proc_res = compile_test(config, props, testfile);
if !proc_res.status.success() {
fatal_proc_rec("compilation failed!", &proc_res);
}
exec_compiled_test(config, props, testfile)
} else {
jit_test(config, props, testfile)
};
// The value our Makefile configures valgrind to return on failure
const VALGRIND_ERR: i32 = 100;
if proc_res.status.code() == Some(VALGRIND_ERR) {
fatal_proc_rec("run-fail test isn't valgrind-clean!", &proc_res);
}
let output_to_check = get_output(props, &proc_res);
check_correct_failure_status(&proc_res);
check_error_patterns(props, testfile, &output_to_check, &proc_res);
}
fn check_correct_failure_status(proc_res: &ProcRes) {
// The value the rust runtime returns on failure
const RUST_ERR: i32 = 101;
if proc_res.status.code() != Some(RUST_ERR) {
fatal_proc_rec(
&format!("failure produced the wrong error: {}",
proc_res.status),
proc_res);
}
}
2014-04-16 04:56:39 +00:00
fn run_rpass_test(config: &Config, props: &TestProps, testfile: &Path) {
if !config.jit {
let mut proc_res = compile_test(config, props, testfile);
if !proc_res.status.success() {
fatal_proc_rec("compilation failed!", &proc_res);
}
proc_res = exec_compiled_test(config, props, testfile);
if !proc_res.status.success() {
fatal_proc_rec("test run failed!", &proc_res);
}
} else {
let proc_res = jit_test(config, props, testfile);
if !proc_res.status.success() {
fatal_proc_rec("jit failed!", &proc_res);
}
}
}
fn run_valgrind_test(config: &Config, props: &TestProps, testfile: &Path) {
if config.valgrind_path.is_none() {
assert!(!config.force_valgrind);
return run_rpass_test(config, props, testfile);
}
let mut proc_res = compile_test(config, props, testfile);
if !proc_res.status.success() {
fatal_proc_rec("compilation failed!", &proc_res);
}
let mut new_config = config.clone();
new_config.runtool = new_config.valgrind_path.clone();
proc_res = exec_compiled_test(&new_config, props, testfile);
if !proc_res.status.success() {
fatal_proc_rec("test run failed!", &proc_res);
}
}
2014-04-16 04:56:39 +00:00
fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
2012-09-22 02:37:57 +00:00
if props.pp_exact.is_some() {
logv(config, "testing for exact pretty-printing".to_string());
} else {
logv(config, "testing for converging pretty-printing".to_string());
}
let rounds =
match props.pp_exact { Some(_) => 1, None => 2 };
let mut src = String::new();
File::open(testfile).unwrap().read_to_string(&mut src).unwrap();
let mut srcs = vec!(src);
let mut round = 0;
while round < rounds {
logv(config, format!("pretty-printing round {}", round));
let proc_res = print_source(config,
props,
testfile,
2014-07-14 23:37:25 +00:00
srcs[round].to_string(),
&props.pretty_mode);
if !proc_res.status.success() {
fatal_proc_rec(&format!("pretty-printing failed in round {}", round),
&proc_res);
}
let ProcRes{ stdout, .. } = proc_res;
srcs.push(stdout);
round += 1;
}
2013-07-28 16:31:37 +00:00
let mut expected = match props.pp_exact {
Some(ref file) => {
let filepath = testfile.parent().unwrap().join(file);
let mut s = String::new();
File::open(&filepath).unwrap().read_to_string(&mut s).unwrap();
s
}
2015-01-24 14:39:32 +00:00
None => { srcs[srcs.len() - 2].clone() }
};
2015-01-24 14:39:32 +00:00
let mut actual = srcs[srcs.len() - 1].clone();
2011-08-03 23:25:38 +00:00
2012-09-22 02:37:57 +00:00
if props.pp_exact.is_some() {
// Now we have to care about line endings
let cr = "\r".to_string();
actual = actual.replace(&cr, "").to_string();
expected = expected.replace(&cr, "").to_string();
}
compare_source(&expected, &actual);
// If we're only making sure that the output matches then just stop here
if props.pretty_compare_only { return; }
// Finally, let's make sure it actually appears to remain valid code
let proc_res = typecheck_source(config, props, testfile, actual);
if !proc_res.status.success() {
fatal_proc_rec("pretty-printed source does not typecheck", &proc_res);
}
if props.no_pretty_expanded { return }
// additionally, run `--pretty expanded` and try to build it.
2014-07-14 23:37:25 +00:00
let proc_res = print_source(config, props, testfile, srcs[round].clone(), "expanded");
if !proc_res.status.success() {
fatal_proc_rec("pretty-printing (expanded) failed", &proc_res);
}
let ProcRes{ stdout: expanded_src, .. } = proc_res;
let proc_res = typecheck_source(config, props, testfile, expanded_src);
if !proc_res.status.success() {
fatal_proc_rec("pretty-printed source (expanded) does not typecheck",
&proc_res);
}
2012-08-02 00:30:05 +00:00
return;
fn print_source(config: &Config,
props: &TestProps,
testfile: &Path,
src: String,
pretty_type: &str) -> ProcRes {
let aux_dir = aux_output_dir_name(config, testfile);
compose_and_run(config,
testfile,
make_pp_args(config,
props,
testfile,
pretty_type.to_string()),
props.exec_env.clone(),
&config.compile_lib_path,
Some(aux_dir.to_str().unwrap()),
Some(src))
}
fn make_pp_args(config: &Config,
props: &TestProps,
testfile: &Path,
pretty_type: String) -> ProcArgs {
let aux_dir = aux_output_dir_name(config, testfile);
// FIXME (#9639): This needs to handle non-utf8 paths
let mut args = vec!("-".to_string(),
"-Zunstable-options".to_string(),
"--pretty".to_string(),
pretty_type,
format!("--target={}", config.target),
"-L".to_string(),
aux_dir.to_str().unwrap().to_string());
2014-09-17 19:56:31 +00:00
args.extend(split_maybe_args(&config.target_rustcflags).into_iter());
args.extend(split_maybe_args(&props.compile_flags).into_iter());
return ProcArgs {
prog: config.rustc_path.to_str().unwrap().to_string(),
args: args,
};
}
fn compare_source(expected: &str, actual: &str) {
if expected != actual {
error("pretty-printed source does not match expected source");
println!("\n\
expected:\n\
------------------------------------------\n\
2013-09-29 20:18:51 +00:00
{}\n\
------------------------------------------\n\
actual:\n\
------------------------------------------\n\
2013-09-29 20:18:51 +00:00
{}\n\
------------------------------------------\n\
\n",
2012-08-23 00:24:52 +00:00
expected, actual);
panic!();
}
}
2014-04-16 04:56:39 +00:00
fn typecheck_source(config: &Config, props: &TestProps,
testfile: &Path, src: String) -> ProcRes {
let args = make_typecheck_args(config, props, testfile);
compose_and_run_compiler(config, props, testfile, args, Some(src))
}
2014-04-16 04:56:39 +00:00
fn make_typecheck_args(config: &Config, props: &TestProps, testfile: &Path) -> ProcArgs {
let aux_dir = aux_output_dir_name(config, testfile);
let target = if props.force_host {
&*config.host
} else {
&*config.target
};
// FIXME (#9639): This needs to handle non-utf8 paths
let mut args = vec!("-".to_string(),
"-Zno-trans".to_string(),
"--crate-type=lib".to_string(),
format!("--target={}", target),
"-L".to_string(),
config.build_base.to_str().unwrap().to_string(),
"-L".to_string(),
aux_dir.to_str().unwrap().to_string());
2014-09-17 19:56:31 +00:00
args.extend(split_maybe_args(&config.target_rustcflags).into_iter());
args.extend(split_maybe_args(&props.compile_flags).into_iter());
// FIXME (#9639): This needs to handle non-utf8 paths
return ProcArgs {
prog: config.rustc_path.to_str().unwrap().to_string(),
args: args,
};
}
}
2014-04-16 04:56:39 +00:00
fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
let mut config = Config {
target_rustcflags: cleanup_debug_info_options(&config.target_rustcflags),
host_rustcflags: cleanup_debug_info_options(&config.host_rustcflags),
.. config.clone()
2013-02-27 18:35:56 +00:00
};
let config = &mut config;
let DebuggerCommands {
commands,
check_lines,
breakpoint_lines
} = parse_debugger_commands(testfile, "gdb");
let mut cmds = commands.connect("\n");
2013-02-27 18:35:56 +00:00
2014-08-01 23:40:21 +00:00
// compile test file (it should have 'compile-flags:-g' in the header)
let compiler_run_result = compile_test(config, props, testfile);
if !compiler_run_result.status.success() {
fatal_proc_rec("compilation failed!", &compiler_run_result);
2013-02-09 18:09:19 +00:00
}
let exe_file = make_exe_name(config, testfile);
let debugger_run_result;
match &*config.target {
"arm-linux-androideabi" | "aarch64-linux-android" => {
2015-01-27 06:36:25 +00:00
cmds = cmds.replace("run", "continue");
// write debugger script
2015-01-27 06:36:25 +00:00
let mut script_str = String::with_capacity(2048);
script_str.push_str("set charset UTF-8\n");
script_str.push_str(&format!("file {}\n", exe_file.to_str().unwrap()));
2015-01-27 06:36:25 +00:00
script_str.push_str("target remote :5039\n");
script_str.push_str(&format!("set solib-search-path \
./{}/stage2/lib/rustlib/{}/lib/\n",
config.host, config.target));
2015-01-27 06:36:25 +00:00
for line in breakpoint_lines.iter() {
script_str.push_str(&format!("break {:?}:{}\n",
testfile.file_name().unwrap()
.to_string_lossy(),
*line)[..]);
2015-01-27 06:36:25 +00:00
}
script_str.push_str(&cmds);
script_str.push_str("\nquit\n");
2015-01-27 06:36:25 +00:00
debug!("script_str = {}", script_str);
dump_output_file(config,
testfile,
&script_str,
"debugger.script");
procsrv::run("",
&config.adb_path,
None,
2014-11-17 08:39:01 +00:00
&[
"push".to_string(),
exe_file.to_str().unwrap().to_string(),
config.adb_test_dir.clone()
],
vec!(("".to_string(), "".to_string())),
Some("".to_string()))
.expect(&format!("failed to exec `{:?}`", config.adb_path));
procsrv::run("",
&config.adb_path,
None,
2014-11-17 08:39:01 +00:00
&[
"forward".to_string(),
"tcp:5039".to_string(),
"tcp:5039".to_string()
],
vec!(("".to_string(), "".to_string())),
Some("".to_string()))
.expect(&format!("failed to exec `{:?}`", config.adb_path));
let adb_arg = format!("export LD_LIBRARY_PATH={}; \
2015-01-27 06:36:25 +00:00
gdbserver{} :5039 {}/{}",
config.adb_test_dir.clone(),
2015-01-27 06:36:25 +00:00
if config.target.contains("aarch64")
{"64"} else {""},
config.adb_test_dir.clone(),
exe_file.file_name().unwrap().to_str()
.unwrap());
let mut process = procsrv::run_background("",
&config.adb_path
,
None,
2014-11-17 08:39:01 +00:00
&[
"shell".to_string(),
adb_arg.clone()
],
vec!(("".to_string(),
"".to_string())),
Some("".to_string()))
.expect(&format!("failed to exec `{:?}`", config.adb_path));
loop {
//waiting 1 second for gdbserver start
2014-08-01 01:03:20 +00:00
timer::sleep(Duration::milliseconds(1000));
if TcpStream::connect("127.0.0.1:5039").is_ok() {
break
}
}
let tool_path = match config.android_cross_path.to_str() {
Some(x) => x.to_string(),
None => fatal("cannot find android cross path")
};
let debugger_script = make_out_name(config, testfile, "debugger.script");
// FIXME (#9639): This needs to handle non-utf8 paths
let debugger_opts =
vec!("-quiet".to_string(),
"-batch".to_string(),
"-nx".to_string(),
format!("-command={}", debugger_script.to_str().unwrap()));
let mut gdb_path = tool_path;
gdb_path.push_str(&format!("/bin/{}-gdb", config.target));
let procsrv::Result {
out,
err,
status
} = procsrv::run("",
&gdb_path,
None,
&debugger_opts,
vec!(("".to_string(), "".to_string())),
None)
.expect(&format!("failed to exec `{:?}`", gdb_path));
let cmdline = {
let cmdline = make_cmdline("",
&format!("{}-gdb", config.target),
&debugger_opts);
logv(config, format!("executing {}", cmdline));
cmdline
};
debugger_run_result = ProcRes {
status: Status::Normal(status),
stdout: out,
stderr: err,
cmdline: cmdline
};
if process.kill().is_err() {
2015-01-27 06:36:25 +00:00
println!("Adb process is already finished.");
}
}
_=> {
let rust_src_root = find_rust_src_root(config)
.expect("Could not find Rust source root");
let rust_pp_module_rel_path = Path::new("./src/etc");
let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
.to_str()
.unwrap()
.to_string();
// write debugger script
let mut script_str = String::with_capacity(2048);
script_str.push_str("set charset UTF-8\n");
script_str.push_str("show version\n");
match config.gdb_version {
Some(ref version) => {
println!("NOTE: compiletest thinks it is using GDB version {}",
version);
if header::gdb_version_to_int(version) >
header::gdb_version_to_int("7.4") {
// Add the directory containing the pretty printers to
// GDB's script auto loading safe path
script_str.push_str(
&format!("add-auto-load-safe-path {}\n",
rust_pp_module_abs_path.replace(r"\", r"\\"))
);
}
}
_ => {
println!("NOTE: compiletest does not know which version of \
GDB it is using");
}
}
// The following line actually doesn't have to do anything with
// pretty printing, it just tells GDB to print values on one line:
script_str.push_str("set print pretty off\n");
// Add the pretty printer directory to GDB's source-file search path
script_str.push_str(&format!("directory {}\n",
rust_pp_module_abs_path));
// Load the target executable
2015-01-04 04:43:24 +00:00
script_str.push_str(&format!("file {}\n",
exe_file.to_str().unwrap()
.replace(r"\", r"\\")));
// Add line breakpoints
2015-01-31 17:20:46 +00:00
for line in &breakpoint_lines {
std: Rename Show/String to Debug/Display This commit is an implementation of [RFC 565][rfc] which is a stabilization of the `std::fmt` module and the implementations of various formatting traits. Specifically, the following changes were performed: [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0565-show-string-guidelines.md * The `Show` trait is now deprecated, it was renamed to `Debug` * The `String` trait is now deprecated, it was renamed to `Display` * Many `Debug` and `Display` implementations were audited in accordance with the RFC and audited implementations now have the `#[stable]` attribute * Integers and floats no longer print a suffix * Smart pointers no longer print details that they are a smart pointer * Paths with `Debug` are now quoted and escape characters * The `unwrap` methods on `Result` now require `Display` instead of `Debug` * The `Error` trait no longer has a `detail` method and now requires that `Display` must be implemented. With the loss of `String`, this has moved into libcore. * `impl<E: Error> FromError<E> for Box<Error>` now exists * `derive(Show)` has been renamed to `derive(Debug)`. This is not currently warned about due to warnings being emitted on stage1+ While backwards compatibility is attempted to be maintained with a blanket implementation of `Display` for the old `String` trait (and the same for `Show`/`Debug`) this is still a breaking change due to primitives no longer implementing `String` as well as modifications such as `unwrap` and the `Error` trait. Most code is fairly straightforward to update with a rename or tweaks of method calls. [breaking-change] Closes #21436
2015-01-20 23:45:07 +00:00
script_str.push_str(&format!("break '{}':{}\n",
testfile.file_name().unwrap()
.to_string_lossy(),
*line));
}
script_str.push_str(&cmds);
script_str.push_str("\nquit\n");
debug!("script_str = {}", script_str);
dump_output_file(config,
testfile,
&script_str,
"debugger.script");
// run debugger script with gdb
fn debugger() -> &'static str {
if cfg!(windows) {"gdb.exe"} else {"gdb"}
}
let debugger_script = make_out_name(config, testfile, "debugger.script");
// FIXME (#9639): This needs to handle non-utf8 paths
let debugger_opts =
vec!("-quiet".to_string(),
"-batch".to_string(),
"-nx".to_string(),
format!("-command={}", debugger_script.to_str().unwrap()));
let proc_args = ProcArgs {
prog: debugger().to_string(),
args: debugger_opts,
};
let environment = vec![("PYTHONPATH".to_string(), rust_pp_module_abs_path)];
debugger_run_result = compose_and_run(config,
testfile,
proc_args,
environment,
&config.run_lib_path,
None,
None);
}
}
if !debugger_run_result.status.success() {
fatal("gdb failed to execute");
2013-02-09 18:09:19 +00:00
}
check_debugger_output(&debugger_run_result, &check_lines);
}
fn find_rust_src_root(config: &Config) -> Option<PathBuf> {
let mut path = config.src_base.clone();
let path_postfix = Path::new("src/etc/lldb_batchmode.py");
while path.pop() {
2014-10-31 05:03:52 +00:00
if path.join(&path_postfix).is_file() {
return Some(path);
}
}
return None;
}
fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) {
if config.lldb_python_dir.is_none() {
fatal("Can't run LLDB test because LLDB's python path is not set.");
}
let mut config = Config {
target_rustcflags: cleanup_debug_info_options(&config.target_rustcflags),
host_rustcflags: cleanup_debug_info_options(&config.host_rustcflags),
.. config.clone()
};
let config = &mut config;
2014-08-01 23:40:21 +00:00
// compile test file (it should have 'compile-flags:-g' in the header)
let compile_result = compile_test(config, props, testfile);
if !compile_result.status.success() {
fatal_proc_rec("compilation failed!", &compile_result);
}
let exe_file = make_exe_name(config, testfile);
match config.lldb_version {
Some(ref version) => {
println!("NOTE: compiletest thinks it is using LLDB version {}",
version);
}
_ => {
println!("NOTE: compiletest does not know which version of \
LLDB it is using");
}
}
// Parse debugger commands etc from test files
let DebuggerCommands {
commands,
check_lines,
breakpoint_lines,
..
} = parse_debugger_commands(testfile, "lldb");
// Write debugger script:
// We don't want to hang when calling `quit` while the process is still running
let mut script_str = String::from_str("settings set auto-confirm true\n");
// Make LLDB emit its version, so we have it documented in the test output
script_str.push_str("version\n");
// Switch LLDB into "Rust mode"
let rust_src_root = find_rust_src_root(config)
.expect("Could not find Rust source root");
let rust_pp_module_rel_path = Path::new("./src/etc/lldb_rust_formatters.py");
let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
.to_str()
.unwrap()
.to_string();
script_str.push_str(&format!("command script import {}\n",
&rust_pp_module_abs_path[..])[..]);
script_str.push_str("type summary add --no-value ");
script_str.push_str("--python-function lldb_rust_formatters.print_val ");
script_str.push_str("-x \".*\" --category Rust\n");
script_str.push_str("type category enable Rust\n");
// Set breakpoints on every line that contains the string "#break"
2015-01-31 17:20:46 +00:00
for line in &breakpoint_lines {
script_str.push_str(&format!("breakpoint set --line {}\n", line));
}
// Append the other commands
2015-01-31 17:20:46 +00:00
for line in &commands {
script_str.push_str(line);
script_str.push_str("\n");
}
// Finally, quit the debugger
script_str.push_str("\nquit\n");
// Write the script into a file
debug!("script_str = {}", script_str);
dump_output_file(config,
testfile,
&script_str,
"debugger.script");
let debugger_script = make_out_name(config, testfile, "debugger.script");
// Let LLDB execute the script via lldb_batchmode.py
let debugger_run_result = run_lldb(config,
&exe_file,
&debugger_script,
&rust_src_root);
if !debugger_run_result.status.success() {
fatal_proc_rec("Error while running LLDB", &debugger_run_result);
}
check_debugger_output(&debugger_run_result, &check_lines);
fn run_lldb(config: &Config,
test_executable: &Path,
debugger_script: &Path,
rust_src_root: &Path)
-> ProcRes {
// Prepare the lldb_batchmode which executes the debugger script
let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py");
let mut cmd = Command::new("python");
cmd.arg(&lldb_script_path)
.arg(test_executable)
.arg(debugger_script)
.env("PYTHONPATH", config.lldb_python_dir.as_ref().unwrap());
let (status, out, err) = match cmd.output() {
Ok(Output { status, stdout, stderr }) => {
(status,
String::from_utf8(stdout).unwrap(),
String::from_utf8(stderr).unwrap())
},
Err(e) => {
fatal(&format!("Failed to setup Python process for \
LLDB script: {}", e))
}
};
dump_output(config, test_executable, &out, &err);
return ProcRes {
status: Status::Normal(status),
stdout: out,
stderr: err,
std: Rename Show/String to Debug/Display This commit is an implementation of [RFC 565][rfc] which is a stabilization of the `std::fmt` module and the implementations of various formatting traits. Specifically, the following changes were performed: [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0565-show-string-guidelines.md * The `Show` trait is now deprecated, it was renamed to `Debug` * The `String` trait is now deprecated, it was renamed to `Display` * Many `Debug` and `Display` implementations were audited in accordance with the RFC and audited implementations now have the `#[stable]` attribute * Integers and floats no longer print a suffix * Smart pointers no longer print details that they are a smart pointer * Paths with `Debug` are now quoted and escape characters * The `unwrap` methods on `Result` now require `Display` instead of `Debug` * The `Error` trait no longer has a `detail` method and now requires that `Display` must be implemented. With the loss of `String`, this has moved into libcore. * `impl<E: Error> FromError<E> for Box<Error>` now exists * `derive(Show)` has been renamed to `derive(Debug)`. This is not currently warned about due to warnings being emitted on stage1+ While backwards compatibility is attempted to be maintained with a blanket implementation of `Display` for the old `String` trait (and the same for `Show`/`Debug`) this is still a breaking change due to primitives no longer implementing `String` as well as modifications such as `unwrap` and the `Error` trait. Most code is fairly straightforward to update with a rename or tweaks of method calls. [breaking-change] Closes #21436
2015-01-20 23:45:07 +00:00
cmdline: format!("{:?}", cmd)
};
}
}
struct DebuggerCommands {
commands: Vec<String>,
check_lines: Vec<String>,
breakpoint_lines: Vec<uint>,
}
fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str)
-> DebuggerCommands {
let command_directive = format!("{}-command", debugger_prefix);
let check_directive = format!("{}-check", debugger_prefix);
let mut breakpoint_lines = vec!();
let mut commands = vec!();
let mut check_lines = vec!();
let mut counter = 1;
let reader = BufReader::new(File::open(file_path).unwrap());
for line in reader.lines() {
match line {
Ok(line) => {
if line.contains("#break") {
breakpoint_lines.push(counter);
}
header::parse_name_value_directive(
&line,
&command_directive).map(|cmd| {
commands.push(cmd)
});
header::parse_name_value_directive(
&line,
&check_directive).map(|cmd| {
check_lines.push(cmd)
});
}
Err(e) => {
fatal(&format!("Error while parsing debugger commands: {}", e))
}
}
counter += 1;
}
DebuggerCommands {
commands: commands,
check_lines: check_lines,
breakpoint_lines: breakpoint_lines,
}
}
fn cleanup_debug_info_options(options: &Option<String>) -> Option<String> {
if options.is_none() {
return None;
}
// Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS.
let options_to_remove = [
"-O".to_string(),
"-g".to_string(),
"--debuginfo".to_string()
];
let new_options =
2014-09-15 03:27:36 +00:00
split_maybe_args(options).into_iter()
.filter(|x| !options_to_remove.contains(x))
.collect::<Vec<String>>()
.connect(" ");
Some(new_options)
}
fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String]) {
2013-05-14 09:52:12 +00:00
let num_check_lines = check_lines.len();
2013-02-09 18:09:19 +00:00
if num_check_lines > 0 {
// Allow check lines to leave parts unspecified (e.g., uninitialized
// bits in the wrong case of an enum) with the notation "[...]".
let check_fragments: Vec<Vec<String>> =
check_lines.iter().map(|s| {
s
.trim()
2015-02-19 13:36:58 +00:00
.split("[...]")
.map(|x| x.to_string())
.collect()
}).collect();
2013-02-09 18:09:19 +00:00
// check if each line in props.check_lines appears in the
// output (in order)
2015-01-24 14:39:32 +00:00
let mut i = 0;
for line in debugger_run_result.stdout.lines() {
let mut rest = line.trim();
let mut first = true;
let mut failed = false;
2015-01-31 17:20:46 +00:00
for frag in &check_fragments[i] {
let found = if first {
if rest.starts_with(frag) {
Some(0)
} else {
None
}
} else {
2015-02-19 13:36:58 +00:00
rest.find(frag)
};
match found {
None => {
failed = true;
break;
}
Some(i) => {
2015-01-18 00:15:52 +00:00
rest = &rest[(i + frag.len())..];
}
}
first = false;
}
if !failed && rest.len() == 0 {
2015-01-24 14:39:32 +00:00
i += 1;
2013-02-09 18:09:19 +00:00
}
if i == num_check_lines {
// all lines checked
break;
}
}
if i != num_check_lines {
fatal_proc_rec(&format!("line not found in debugger output: {}",
check_lines.get(i).unwrap()),
debugger_run_result);
2013-02-09 18:09:19 +00:00
}
}
}
fn check_error_patterns(props: &TestProps,
testfile: &Path,
output_to_check: &str,
proc_res: &ProcRes) {
if props.error_patterns.is_empty() {
fatal(&format!("no error pattern specified in {:?}", testfile.display()));
}
2015-01-24 14:39:32 +00:00
let mut next_err_idx = 0;
2014-07-14 23:37:25 +00:00
let mut next_err_pat = &props.error_patterns[next_err_idx];
let mut done = false;
for line in output_to_check.lines() {
if line.contains(next_err_pat) {
2014-07-14 23:37:25 +00:00
debug!("found error pattern {}", next_err_pat);
2015-01-24 14:39:32 +00:00
next_err_idx += 1;
2013-05-14 09:52:12 +00:00
if next_err_idx == props.error_patterns.len() {
debug!("found all error patterns");
done = true;
break;
}
2014-07-14 23:37:25 +00:00
next_err_pat = &props.error_patterns[next_err_idx];
}
}
2012-08-02 00:30:05 +00:00
if done { return; }
2015-01-07 16:58:31 +00:00
let missing_patterns = &props.error_patterns[next_err_idx..];
2015-01-24 14:39:32 +00:00
if missing_patterns.len() == 1 {
fatal_proc_rec(&format!("error pattern '{}' not found!", missing_patterns[0]),
proc_res);
} else {
2015-01-31 17:20:46 +00:00
for pattern in missing_patterns {
error(&format!("error pattern '{}' not found!", *pattern));
}
fatal_proc_rec("multiple error patterns not found", proc_res);
}
}
fn check_no_compiler_crash(proc_res: &ProcRes) {
for line in proc_res.stderr.lines() {
if line.starts_with("error: internal compiler error:") {
fatal_proc_rec("compiler encountered internal error",
proc_res);
}
}
}
fn check_forbid_output(props: &TestProps,
output_to_check: &str,
proc_res: &ProcRes) {
2015-01-31 17:20:46 +00:00
for pat in &props.forbid_output {
if output_to_check.contains(pat) {
fatal_proc_rec("forbidden pattern found in compiler output", proc_res);
}
}
}
fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
testfile: &Path,
proc_res: &ProcRes) {
// true if we found the error in question
2014-12-30 18:51:18 +00:00
let mut found_flags: Vec<_> = repeat(false).take(expected_errors.len()).collect();
if proc_res.status.success() {
fatal("process did not return an error status");
}
let prefixes = expected_errors.iter().map(|ee| {
std: Rename Show/String to Debug/Display This commit is an implementation of [RFC 565][rfc] which is a stabilization of the `std::fmt` module and the implementations of various formatting traits. Specifically, the following changes were performed: [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0565-show-string-guidelines.md * The `Show` trait is now deprecated, it was renamed to `Debug` * The `String` trait is now deprecated, it was renamed to `Display` * Many `Debug` and `Display` implementations were audited in accordance with the RFC and audited implementations now have the `#[stable]` attribute * Integers and floats no longer print a suffix * Smart pointers no longer print details that they are a smart pointer * Paths with `Debug` are now quoted and escape characters * The `unwrap` methods on `Result` now require `Display` instead of `Debug` * The `Error` trait no longer has a `detail` method and now requires that `Display` must be implemented. With the loss of `String`, this has moved into libcore. * `impl<E: Error> FromError<E> for Box<Error>` now exists * `derive(Show)` has been renamed to `derive(Debug)`. This is not currently warned about due to warnings being emitted on stage1+ While backwards compatibility is attempted to be maintained with a blanket implementation of `Display` for the old `String` trait (and the same for `Show`/`Debug`) this is still a breaking change due to primitives no longer implementing `String` as well as modifications such as `unwrap` and the `Error` trait. Most code is fairly straightforward to update with a rename or tweaks of method calls. [breaking-change] Closes #21436
2015-01-20 23:45:07 +00:00
format!("{}:{}:", testfile.display(), ee.line)
}).collect::<Vec<String>>();
fn prefix_matches(line: &str, prefix: &str) -> bool {
use std::ascii::AsciiExt;
// On windows just translate all '\' path separators to '/'
let line = line.replace(r"\", "/");
if cfg!(windows) {
line.to_ascii_lowercase().starts_with(&prefix.to_ascii_lowercase())
} else {
line.starts_with(prefix)
}
}
2015-01-12 04:18:52 +00:00
// A multi-line error will have followup lines which will always
// start with one of these strings.
fn continuation( line: &str) -> bool {
line.starts_with(" expected") ||
line.starts_with(" found") ||
// 1234
// Should have 4 spaces: see issue 18946
line.starts_with("(")
}
// Scan and extract our error/warning messages,
// which look like:
// filename:line1:col1: line2:col2: *error:* msg
// filename:line1:col1: line2:col2: *warning:* msg
// where line1:col1: is the starting point, line2:col2:
// is the ending point, and * represents ANSI color codes.
for line in proc_res.stderr.lines() {
let mut was_expected = false;
for (i, ee) in expected_errors.iter().enumerate() {
2014-07-14 23:37:25 +00:00
if !found_flags[i] {
debug!("prefix={} ee.kind={} ee.msg={} line={}",
prefixes[i],
ee.kind,
ee.msg,
line);
if (prefix_matches(line, &prefixes[i]) || continuation(line)) &&
line.contains(&ee.kind) &&
line.contains(&ee.msg) {
found_flags[i] = true;
was_expected = true;
break;
}
}
}
// ignore this msg which gets printed at the end
if line.contains("aborting due to") {
was_expected = true;
}
if !was_expected && is_compiler_error_or_warning(line) {
fatal_proc_rec(&format!("unexpected compiler error or warning: '{}'",
line),
proc_res);
}
}
for (i, &flag) in found_flags.iter().enumerate() {
if !flag {
2014-07-14 23:37:25 +00:00
let ee = &expected_errors[i];
fatal_proc_rec(&format!("expected {} on line {} not found: {}",
ee.kind, ee.line, ee.msg),
proc_res);
}
}
}
fn is_compiler_error_or_warning(line: &str) -> bool {
2015-01-24 14:39:32 +00:00
let mut i = 0;
return
scan_until_char(line, ':', &mut i) &&
scan_char(line, ':', &mut i) &&
scan_integer(line, &mut i) &&
scan_char(line, ':', &mut i) &&
scan_integer(line, &mut i) &&
scan_char(line, ':', &mut i) &&
scan_char(line, ' ', &mut i) &&
scan_integer(line, &mut i) &&
scan_char(line, ':', &mut i) &&
scan_integer(line, &mut i) &&
scan_char(line, ' ', &mut i) &&
(scan_string(line, "error", &mut i) ||
scan_string(line, "warning", &mut i));
}
fn scan_until_char(haystack: &str, needle: char, idx: &mut uint) -> bool {
if *idx >= haystack.len() {
return false;
}
2015-01-18 00:15:52 +00:00
let opt = haystack[(*idx)..].find(needle);
if opt.is_none() {
return false;
}
*idx = opt.unwrap();
return true;
}
fn scan_char(haystack: &str, needle: char, idx: &mut uint) -> bool {
if *idx >= haystack.len() {
return false;
}
2013-06-10 11:46:36 +00:00
let range = haystack.char_range_at(*idx);
2012-11-27 04:05:19 +00:00
if range.ch != needle {
return false;
}
2012-11-27 04:05:19 +00:00
*idx = range.next;
return true;
}
fn scan_integer(haystack: &str, idx: &mut uint) -> bool {
let mut i = *idx;
while i < haystack.len() {
2013-06-10 11:46:36 +00:00
let range = haystack.char_range_at(i);
2012-11-27 04:05:19 +00:00
if range.ch < '0' || '9' < range.ch {
break;
}
2012-11-27 04:05:19 +00:00
i = range.next;
}
if i == *idx {
return false;
}
*idx = i;
return true;
}
fn scan_string(haystack: &str, needle: &str, idx: &mut uint) -> bool {
let mut haystack_i = *idx;
2015-01-24 14:39:32 +00:00
let mut needle_i = 0;
while needle_i < needle.len() {
if haystack_i >= haystack.len() {
return false;
}
2013-06-10 11:46:36 +00:00
let range = haystack.char_range_at(haystack_i);
2012-11-27 04:05:19 +00:00
haystack_i = range.next;
if !scan_char(needle, range.ch, &mut needle_i) {
return false;
}
}
*idx = haystack_i;
return true;
}
struct ProcArgs {
prog: String,
args: Vec<String>,
}
struct ProcRes {
status: Status,
stdout: String,
stderr: String,
cmdline: String,
}
enum Status {
Parsed(i32),
Normal(ExitStatus),
}
impl Status {
fn code(&self) -> Option<i32> {
match *self {
Status::Parsed(i) => Some(i),
Status::Normal(ref e) => e.code(),
}
}
fn success(&self) -> bool {
match *self {
Status::Parsed(i) => i == 0,
Status::Normal(ref e) => e.success(),
}
}
}
impl fmt::Display for Status {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Status::Parsed(i) => write!(f, "exit code: {}", i),
Status::Normal(ref e) => e.fmt(f),
}
}
}
2014-04-16 04:56:39 +00:00
fn compile_test(config: &Config, props: &TestProps,
testfile: &Path) -> ProcRes {
2014-11-17 08:39:01 +00:00
compile_test_(config, props, testfile, &[])
}
2014-04-16 04:56:39 +00:00
fn jit_test(config: &Config, props: &TestProps, testfile: &Path) -> ProcRes {
2014-11-17 08:39:01 +00:00
compile_test_(config, props, testfile, &["--jit".to_string()])
}
2014-04-16 04:56:39 +00:00
fn compile_test_(config: &Config, props: &TestProps,
testfile: &Path, extra_args: &[String]) -> ProcRes {
let aux_dir = aux_output_dir_name(config, testfile);
// FIXME (#9639): This needs to handle non-utf8 paths
2014-09-17 19:56:31 +00:00
let mut link_args = vec!("-L".to_string(),
aux_dir.to_str().unwrap().to_string());
link_args.extend(extra_args.iter().cloned());
let args = make_compile_args(config,
props,
2014-09-17 19:56:31 +00:00
link_args,
2014-11-21 18:50:44 +00:00
|a, b| TargetLocation::ThisFile(make_exe_name(a, b)), testfile);
compose_and_run_compiler(config, props, testfile, args, None)
}
2014-04-16 04:56:39 +00:00
fn exec_compiled_test(config: &Config, props: &TestProps,
testfile: &Path) -> ProcRes {
2013-07-02 19:47:32 +00:00
let env = props.exec_env.clone();
match &*config.target {
"arm-linux-androideabi" | "aarch64-linux-android" => {
_arm_exec_compiled_test(config, props, testfile, env)
2013-05-04 01:35:07 +00:00
}
2013-05-04 01:35:07 +00:00
_=> {
let aux_dir = aux_output_dir_name(config, testfile);
compose_and_run(config,
testfile,
2013-05-04 01:35:07 +00:00
make_run_args(config, props, testfile),
env,
&config.run_lib_path,
Some(aux_dir.to_str().unwrap()),
None)
}
}
}
fn compose_and_run_compiler(
2014-04-16 04:56:39 +00:00
config: &Config,
props: &TestProps,
testfile: &Path,
args: ProcArgs,
input: Option<String>) -> ProcRes {
if !props.aux_builds.is_empty() {
ensure_dir(&aux_output_dir_name(config, testfile));
}
let aux_dir = aux_output_dir_name(config, testfile);
// FIXME (#9639): This needs to handle non-utf8 paths
let extra_link_args = vec!("-L".to_string(), aux_dir.to_str().unwrap().to_string());
2015-01-31 17:20:46 +00:00
for rel_ab in &props.aux_builds {
let abs_ab = config.aux_base.join(rel_ab);
let aux_props = header::load_props(&abs_ab);
2014-09-17 19:56:31 +00:00
let mut crate_type = if aux_props.no_prefer_dynamic {
Vec::new()
} else {
vec!("--crate-type=dylib".to_string())
};
2014-09-17 19:56:31 +00:00
crate_type.extend(extra_link_args.clone().into_iter());
let aux_args =
make_compile_args(config,
&aux_props,
2014-09-17 19:56:31 +00:00
crate_type,
Redesign output flags for rustc This commit removes the -c, --emit-llvm, -s, --rlib, --dylib, --staticlib, --lib, and --bin flags from rustc, adding the following flags: * --emit=[asm,ir,bc,obj,link] * --crate-type=[dylib,rlib,staticlib,bin,lib] The -o option has also been redefined to be used for *all* flavors of outputs. This means that we no longer ignore it for libraries. The --out-dir remains the same as before. The new logic for files that rustc emits is as follows: 1. Output types are dictated by the --emit flag. The default value is --emit=link, and this option can be passed multiple times and have all options stacked on one another. 2. Crate types are dictated by the --crate-type flag and the #[crate_type] attribute. The flags can be passed many times and stack with the crate attribute. 3. If the -o flag is specified, and only one output type is specified, the output will be emitted at this location. If more than one output type is specified, then the filename of -o is ignored, and all output goes in the directory that -o specifies. The -o option always ignores the --out-dir option. 4. If the --out-dir flag is specified, all output goes in this directory. 5. If -o and --out-dir are both not present, all output goes in the current directory of the process. 6. When multiple output types are specified, the filestem of all output is the same as the name of the CrateId (derived from a crate attribute or from the filestem of the crate file). Closes #7791 Closes #11056 Closes #11667
2014-02-03 23:27:54 +00:00
|a,b| {
let f = make_lib_name(a, b, testfile);
let parent = f.parent().unwrap();
TargetLocation::ThisDirectory(parent.to_path_buf())
},
&abs_ab);
let auxres = compose_and_run(config,
&abs_ab,
aux_args,
Vec::new(),
&config.compile_lib_path,
Some(aux_dir.to_str().unwrap()),
None);
if !auxres.status.success() {
fatal_proc_rec(
&format!("auxiliary build of {:?} failed to compile: ",
abs_ab.display()),
&auxres);
}
match &*config.target {
"arm-linux-androideabi" | "aarch64-linux-android" => {
_arm_push_aux_shared_library(config, testfile);
}
_ => {}
}
}
compose_and_run(config,
testfile,
args,
Vec::new(),
&config.compile_lib_path,
Some(aux_dir.to_str().unwrap()),
input)
}
fn ensure_dir(path: &Path) {
if path.is_dir() { return; }
fs::create_dir(path).unwrap();
}
2014-04-16 04:56:39 +00:00
fn compose_and_run(config: &Config, testfile: &Path,
ProcArgs{ args, prog }: ProcArgs,
procenv: Vec<(String, String)> ,
lib_path: &str,
aux_path: Option<&str>,
input: Option<String>) -> ProcRes {
2012-08-02 00:30:05 +00:00
return program_output(config, testfile, lib_path,
prog, aux_path, args, procenv, input);
}
Redesign output flags for rustc This commit removes the -c, --emit-llvm, -s, --rlib, --dylib, --staticlib, --lib, and --bin flags from rustc, adding the following flags: * --emit=[asm,ir,bc,obj,link] * --crate-type=[dylib,rlib,staticlib,bin,lib] The -o option has also been redefined to be used for *all* flavors of outputs. This means that we no longer ignore it for libraries. The --out-dir remains the same as before. The new logic for files that rustc emits is as follows: 1. Output types are dictated by the --emit flag. The default value is --emit=link, and this option can be passed multiple times and have all options stacked on one another. 2. Crate types are dictated by the --crate-type flag and the #[crate_type] attribute. The flags can be passed many times and stack with the crate attribute. 3. If the -o flag is specified, and only one output type is specified, the output will be emitted at this location. If more than one output type is specified, then the filename of -o is ignored, and all output goes in the directory that -o specifies. The -o option always ignores the --out-dir option. 4. If the --out-dir flag is specified, all output goes in this directory. 5. If -o and --out-dir are both not present, all output goes in the current directory of the process. 6. When multiple output types are specified, the filestem of all output is the same as the name of the CrateId (derived from a crate attribute or from the filestem of the crate file). Closes #7791 Closes #11056 Closes #11667
2014-02-03 23:27:54 +00:00
enum TargetLocation {
ThisFile(PathBuf),
ThisDirectory(PathBuf),
Redesign output flags for rustc This commit removes the -c, --emit-llvm, -s, --rlib, --dylib, --staticlib, --lib, and --bin flags from rustc, adding the following flags: * --emit=[asm,ir,bc,obj,link] * --crate-type=[dylib,rlib,staticlib,bin,lib] The -o option has also been redefined to be used for *all* flavors of outputs. This means that we no longer ignore it for libraries. The --out-dir remains the same as before. The new logic for files that rustc emits is as follows: 1. Output types are dictated by the --emit flag. The default value is --emit=link, and this option can be passed multiple times and have all options stacked on one another. 2. Crate types are dictated by the --crate-type flag and the #[crate_type] attribute. The flags can be passed many times and stack with the crate attribute. 3. If the -o flag is specified, and only one output type is specified, the output will be emitted at this location. If more than one output type is specified, then the filename of -o is ignored, and all output goes in the directory that -o specifies. The -o option always ignores the --out-dir option. 4. If the --out-dir flag is specified, all output goes in this directory. 5. If -o and --out-dir are both not present, all output goes in the current directory of the process. 6. When multiple output types are specified, the filestem of all output is the same as the name of the CrateId (derived from a crate attribute or from the filestem of the crate file). Closes #7791 Closes #11056 Closes #11667
2014-02-03 23:27:54 +00:00
}
2015-01-05 03:05:29 +00:00
fn make_compile_args<F>(config: &Config,
props: &TestProps,
extras: Vec<String> ,
xform: F,
testfile: &Path)
-> ProcArgs where
F: FnOnce(&Config, &Path) -> TargetLocation,
{
let xform_file = xform(config, testfile);
let target = if props.force_host {
&*config.host
} else {
&*config.target
};
// FIXME (#9639): This needs to handle non-utf8 paths
let mut args = vec!(testfile.to_str().unwrap().to_string(),
"-L".to_string(),
config.build_base.to_str().unwrap().to_string(),
format!("--target={}", target));
args.push_all(&extras);
if !props.no_prefer_dynamic {
args.push("-C".to_string());
args.push("prefer-dynamic".to_string());
}
Redesign output flags for rustc This commit removes the -c, --emit-llvm, -s, --rlib, --dylib, --staticlib, --lib, and --bin flags from rustc, adding the following flags: * --emit=[asm,ir,bc,obj,link] * --crate-type=[dylib,rlib,staticlib,bin,lib] The -o option has also been redefined to be used for *all* flavors of outputs. This means that we no longer ignore it for libraries. The --out-dir remains the same as before. The new logic for files that rustc emits is as follows: 1. Output types are dictated by the --emit flag. The default value is --emit=link, and this option can be passed multiple times and have all options stacked on one another. 2. Crate types are dictated by the --crate-type flag and the #[crate_type] attribute. The flags can be passed many times and stack with the crate attribute. 3. If the -o flag is specified, and only one output type is specified, the output will be emitted at this location. If more than one output type is specified, then the filename of -o is ignored, and all output goes in the directory that -o specifies. The -o option always ignores the --out-dir option. 4. If the --out-dir flag is specified, all output goes in this directory. 5. If -o and --out-dir are both not present, all output goes in the current directory of the process. 6. When multiple output types are specified, the filestem of all output is the same as the name of the CrateId (derived from a crate attribute or from the filestem of the crate file). Closes #7791 Closes #11056 Closes #11667
2014-02-03 23:27:54 +00:00
let path = match xform_file {
2014-11-21 18:50:44 +00:00
TargetLocation::ThisFile(path) => {
args.push("-o".to_string());
path
}
2014-11-21 18:50:44 +00:00
TargetLocation::ThisDirectory(path) => {
args.push("--out-dir".to_string());
path
}
Redesign output flags for rustc This commit removes the -c, --emit-llvm, -s, --rlib, --dylib, --staticlib, --lib, and --bin flags from rustc, adding the following flags: * --emit=[asm,ir,bc,obj,link] * --crate-type=[dylib,rlib,staticlib,bin,lib] The -o option has also been redefined to be used for *all* flavors of outputs. This means that we no longer ignore it for libraries. The --out-dir remains the same as before. The new logic for files that rustc emits is as follows: 1. Output types are dictated by the --emit flag. The default value is --emit=link, and this option can be passed multiple times and have all options stacked on one another. 2. Crate types are dictated by the --crate-type flag and the #[crate_type] attribute. The flags can be passed many times and stack with the crate attribute. 3. If the -o flag is specified, and only one output type is specified, the output will be emitted at this location. If more than one output type is specified, then the filename of -o is ignored, and all output goes in the directory that -o specifies. The -o option always ignores the --out-dir option. 4. If the --out-dir flag is specified, all output goes in this directory. 5. If -o and --out-dir are both not present, all output goes in the current directory of the process. 6. When multiple output types are specified, the filestem of all output is the same as the name of the CrateId (derived from a crate attribute or from the filestem of the crate file). Closes #7791 Closes #11056 Closes #11667
2014-02-03 23:27:54 +00:00
};
args.push(path.to_str().unwrap().to_string());
2014-02-11 21:51:08 +00:00
if props.force_host {
2014-09-17 19:56:31 +00:00
args.extend(split_maybe_args(&config.host_rustcflags).into_iter());
2014-02-11 21:51:08 +00:00
} else {
2014-09-17 19:56:31 +00:00
args.extend(split_maybe_args(&config.target_rustcflags).into_iter());
2014-02-11 21:51:08 +00:00
}
2014-09-17 19:56:31 +00:00
args.extend(split_maybe_args(&props.compile_flags).into_iter());
return ProcArgs {
prog: config.rustc_path.to_str().unwrap().to_string(),
args: args,
};
}
fn make_lib_name(config: &Config, auxfile: &Path, testfile: &Path) -> PathBuf {
// what we return here is not particularly important, as it
// happens; rustc ignores everything except for the directory.
let auxname = output_testname(auxfile);
aux_output_dir_name(config, testfile).join(&auxname)
}
fn make_exe_name(config: &Config, testfile: &Path) -> PathBuf {
let mut f = output_base_name(config, testfile);
std: Add a new `env` module This is an implementation of [RFC 578][rfc] which adds a new `std::env` module to replace most of the functionality in the current `std::os` module. More details can be found in the RFC itself, but as a summary the following methods have all been deprecated: [rfc]: https://github.com/rust-lang/rfcs/pull/578 * `os::args_as_bytes` => `env::args` * `os::args` => `env::args` * `os::consts` => `env::consts` * `os::dll_filename` => no replacement, use `env::consts` directly * `os::page_size` => `env::page_size` * `os::make_absolute` => use `env::current_dir` + `join` instead * `os::getcwd` => `env::current_dir` * `os::change_dir` => `env::set_current_dir` * `os::homedir` => `env::home_dir` * `os::tmpdir` => `env::temp_dir` * `os::join_paths` => `env::join_paths` * `os::split_paths` => `env::split_paths` * `os::self_exe_name` => `env::current_exe` * `os::self_exe_path` => use `env::current_exe` + `pop` * `os::set_exit_status` => `env::set_exit_status` * `os::get_exit_status` => `env::get_exit_status` * `os::env` => `env::vars` * `os::env_as_bytes` => `env::vars` * `os::getenv` => `env::var` or `env::var_string` * `os::getenv_as_bytes` => `env::var` * `os::setenv` => `env::set_var` * `os::unsetenv` => `env::remove_var` Many function signatures have also been tweaked for various purposes, but the main changes were: * `Vec`-returning APIs now all return iterators instead * All APIs are now centered around `OsString` instead of `Vec<u8>` or `String`. There is currently on convenience API, `env::var_string`, which can be used to get the value of an environment variable as a unicode `String`. All old APIs are `#[deprecated]` in-place and will remain for some time to allow for migrations. The semantics of the APIs have been tweaked slightly with regard to dealing with invalid unicode (panic instead of replacement). The new `std::env` module is all contained within the `env` feature, so crates must add the following to access the new APIs: #![feature(env)] [breaking-change]
2015-01-27 20:20:58 +00:00
if !env::consts::EXE_SUFFIX.is_empty() {
let mut fname = f.file_name().unwrap().to_os_string();
fname.push_os_str(OsStr::from_str(env::consts::EXE_SUFFIX));
f.set_file_name(&fname);
}
f
}
2014-04-16 04:56:39 +00:00
fn make_run_args(config: &Config, props: &TestProps, testfile: &Path) ->
ProcArgs {
// If we've got another tool to run under (valgrind),
// then split apart its command
let mut args = split_maybe_args(&config.runtool);
let exe_file = make_exe_name(config, testfile);
// FIXME (#9639): This needs to handle non-utf8 paths
args.push(exe_file.to_str().unwrap().to_string());
// Add the arguments in the run_flags directive
2014-09-17 19:56:31 +00:00
args.extend(split_maybe_args(&props.run_flags).into_iter());
2014-12-30 18:51:18 +00:00
let prog = args.remove(0);
return ProcArgs {
prog: prog,
args: args,
};
}
fn split_maybe_args(argstr: &Option<String>) -> Vec<String> {
match *argstr {
Some(ref s) => {
s
.split(' ')
.filter_map(|s| {
2014-12-11 03:46:38 +00:00
if s.chars().all(|c| c.is_whitespace()) {
None
} else {
Some(s.to_string())
}
}).collect()
2013-03-26 03:39:10 +00:00
}
None => Vec::new()
}
}
fn program_output(config: &Config, testfile: &Path, lib_path: &str, prog: String,
aux_path: Option<&str>, args: Vec<String>,
env: Vec<(String, String)>,
input: Option<String>) -> ProcRes {
let cmdline =
{
let cmdline = make_cmdline(lib_path,
&prog,
&args);
logv(config, format!("executing {}", cmdline));
cmdline
};
let procsrv::Result {
out,
err,
status
} = procsrv::run(lib_path,
&prog,
aux_path,
&args,
env,
input).expect(&format!("failed to exec `{}`", prog));
dump_output(config, testfile, &out, &err);
return ProcRes {
status: Status::Normal(status),
stdout: out,
stderr: err,
cmdline: cmdline,
};
}
fn make_cmdline(libpath: &str, prog: &str, args: &[String]) -> String {
use util;
// Linux and mac don't require adjusting the library search path
if cfg!(unix) {
format!("{} {}", prog, args.connect(" "))
} else {
// Build the LD_LIBRARY_PATH variable as it would be seen on the command line
// for diagnostic purposes
fn lib_path_cmd_prefix(path: &str) -> String {
format!("{}=\"{}\"", util::lib_path_env_var(), util::make_new_path(path))
}
Clean up rustc warnings. compiletest: compact "linux" "macos" etc.as "unix". liballoc: remove a superfluous "use". libcollections: remove invocations of deprecated methods in favor of their suggested replacements and use "_" for a loop counter. libcoretest: remove invocations of deprecated methods; also add "allow(deprecated)" for testing a deprecated method itself. libglob: use "cfg_attr". libgraphviz: add a test for one of data constructors. libgreen: remove a superfluous "use". libnum: "allow(type_overflow)" for type cast into u8 in a test code. librustc: names of static variables should be in upper case. libserialize: v[i] instead of get(). libstd/ascii: to_lowercase() instead of to_lower(). libstd/bitflags: modify AnotherSetOfFlags to use i8 as its backend. It will serve better for testing various aspects of bitflags!. libstd/collections: "allow(deprecated)" for testing a deprecated method itself. libstd/io: remove invocations of deprecated methods and superfluous "use". Also add #[test] where it was missing. libstd/num: introduce a helper function to effectively remove invocations of a deprecated method. libstd/path and rand: remove invocations of deprecated methods and superfluous "use". libstd/task and libsync/comm: "allow(deprecated)" for testing a deprecated method itself. libsync/deque: remove superfluous "unsafe". libsync/mutex and once: names of static variables should be in upper case. libterm: introduce a helper function to effectively remove invocations of a deprecated method. We still see a few warnings about using obsoleted native::task::spawn() in the test modules for libsync. I'm not sure how I should replace them with std::task::TaksBuilder and native::task::NativeTaskBuilder (dependency to libstd?) Signed-off-by: NODA, Kai <nodakai@gmail.com>
2014-10-05 10:11:17 +00:00
format!("{} {} {}", lib_path_cmd_prefix(libpath), prog, args.connect(" "))
}
}
2014-04-16 04:56:39 +00:00
fn dump_output(config: &Config, testfile: &Path, out: &str, err: &str) {
dump_output_file(config, testfile, out, "out");
dump_output_file(config, testfile, err, "err");
maybe_dump_to_stdout(config, out, err);
}
2014-04-16 04:56:39 +00:00
fn dump_output_file(config: &Config, testfile: &Path,
out: &str, extension: &str) {
let outfile = make_out_name(config, testfile, extension);
File::create(&outfile).unwrap().write_all(out.as_bytes()).unwrap();
}
fn make_out_name(config: &Config, testfile: &Path, extension: &str) -> PathBuf {
output_base_name(config, testfile).with_extension(extension)
}
fn aux_output_dir_name(config: &Config, testfile: &Path) -> PathBuf {
2014-09-17 19:56:31 +00:00
let f = output_base_name(config, testfile);
let mut fname = f.file_name().unwrap().to_os_string();
fname.push_os_str(OsStr::from_str("libaux"));
f.with_file_name(&fname)
}
fn output_testname(testfile: &Path) -> PathBuf {
PathBuf::new(testfile.file_stem().unwrap())
}
fn output_base_name(config: &Config, testfile: &Path) -> PathBuf {
config.build_base
.join(&output_testname(testfile))
.with_extension(&config.stage_id)
}
2014-04-16 04:56:39 +00:00
fn maybe_dump_to_stdout(config: &Config, out: &str, err: &str) {
if config.verbose {
println!("------{}------------------------------", "stdout");
println!("{}", out);
println!("------{}------------------------------", "stderr");
println!("{}", err);
println!("------------------------------------------");
}
}
fn error(err: &str) { println!("\nerror: {}", err); }
fn fatal(err: &str) -> ! { error(err); panic!(); }
fn fatal_proc_rec(err: &str, proc_res: &ProcRes) -> ! {
print!("\n\
2013-09-29 20:18:51 +00:00
error: {}\n\
status: {}\n\
2013-09-29 20:18:51 +00:00
command: {}\n\
stdout:\n\
------------------------------------------\n\
2013-09-29 20:18:51 +00:00
{}\n\
------------------------------------------\n\
stderr:\n\
------------------------------------------\n\
2013-09-29 20:18:51 +00:00
{}\n\
------------------------------------------\n\
\n",
err, proc_res.status, proc_res.cmdline, proc_res.stdout,
proc_res.stderr);
panic!();
}
2013-05-04 01:35:07 +00:00
fn _arm_exec_compiled_test(config: &Config,
props: &TestProps,
testfile: &Path,
env: Vec<(String, String)>)
-> ProcRes {
2013-05-04 01:35:07 +00:00
let args = make_run_args(config, props, testfile);
let cmdline = make_cmdline("",
&args.prog,
&args.args);
2013-05-04 01:35:07 +00:00
// get bare program string
let mut tvec: Vec<String> = args.prog
.split('/')
.map(|ts| ts.to_string())
.collect();
let prog_short = tvec.pop().unwrap();
2013-05-04 01:35:07 +00:00
// copy to target
let copy_result = procsrv::run("",
&config.adb_path,
None,
2014-11-17 08:39:01 +00:00
&[
"push".to_string(),
args.prog.clone(),
config.adb_test_dir.clone()
],
vec!(("".to_string(), "".to_string())),
Some("".to_string()))
.expect(&format!("failed to exec `{}`", config.adb_path));
if config.verbose {
println!("push ({}) {} {} {}",
config.target,
args.prog,
copy_result.out,
copy_result.err);
}
logv(config, format!("executing ({}) {}", config.target, cmdline));
let mut runargs = Vec::new();
2013-06-01 08:27:30 +00:00
// run test via adb_run_wrapper
runargs.push("shell".to_string());
for (key, val) in env {
runargs.push(format!("{}={}", key, val));
}
runargs.push(format!("{}/../adb_run_wrapper.sh", config.adb_test_dir));
runargs.push(format!("{}", config.adb_test_dir));
runargs.push(format!("{}", prog_short));
2015-01-31 17:20:46 +00:00
for tv in &args.args {
runargs.push(tv.to_string());
2013-06-01 08:27:30 +00:00
}
procsrv::run("",
&config.adb_path,
None,
&runargs,
vec!(("".to_string(), "".to_string())), Some("".to_string()))
.expect(&format!("failed to exec `{}`", config.adb_path));
2013-06-01 08:27:30 +00:00
// get exitcode of result
runargs = Vec::new();
runargs.push("shell".to_string());
runargs.push("cat".to_string());
runargs.push(format!("{}/{}.exitcode", config.adb_test_dir, prog_short));
2013-06-01 08:27:30 +00:00
let procsrv::Result{ out: exitcode_out, err: _, status: _ } =
procsrv::run("",
&config.adb_path,
None,
&runargs,
vec!(("".to_string(), "".to_string())),
Some("".to_string()))
.expect(&format!("failed to exec `{}`", config.adb_path));
2013-06-01 08:27:30 +00:00
let mut exitcode: i32 = 0;
for c in exitcode_out.chars() {
if !c.is_numeric() { break; }
2013-06-01 08:27:30 +00:00
exitcode = exitcode * 10 + match c {
'0' ... '9' => c as i32 - ('0' as i32),
2013-06-01 08:27:30 +00:00
_ => 101,
}
2013-06-01 08:27:30 +00:00
}
// get stdout of result
runargs = Vec::new();
runargs.push("shell".to_string());
runargs.push("cat".to_string());
runargs.push(format!("{}/{}.stdout", config.adb_test_dir, prog_short));
2013-06-01 08:27:30 +00:00
let procsrv::Result{ out: stdout_out, err: _, status: _ } =
procsrv::run("",
&config.adb_path,
None,
&runargs,
vec!(("".to_string(), "".to_string())),
Some("".to_string()))
.expect(&format!("failed to exec `{}`", config.adb_path));
// get stderr of result
runargs = Vec::new();
runargs.push("shell".to_string());
runargs.push("cat".to_string());
runargs.push(format!("{}/{}.stderr", config.adb_test_dir, prog_short));
2013-06-01 08:27:30 +00:00
let procsrv::Result{ out: stderr_out, err: _, status: _ } =
procsrv::run("",
&config.adb_path,
None,
&runargs,
vec!(("".to_string(), "".to_string())),
Some("".to_string()))
.expect(&format!("failed to exec `{}`", config.adb_path));
dump_output(config,
testfile,
&stdout_out,
&stderr_out);
ProcRes {
status: Status::Parsed(exitcode),
stdout: stdout_out,
stderr: stderr_out,
cmdline: cmdline
}
}
2014-04-16 04:56:39 +00:00
fn _arm_push_aux_shared_library(config: &Config, testfile: &Path) {
let tdir = aux_output_dir_name(config, testfile);
2013-05-04 01:35:07 +00:00
let dirs = fs::read_dir(&tdir).unwrap();
for file in dirs {
let file = file.unwrap().path();
if file.extension().and_then(|s| s.to_str()) == Some("so") {
// FIXME (#9639): This needs to handle non-utf8 paths
let copy_result = procsrv::run("",
&config.adb_path,
None,
2014-11-17 08:39:01 +00:00
&[
"push".to_string(),
file.to_str()
.unwrap()
.to_string(),
config.adb_test_dir.to_string(),
],
vec!(("".to_string(),
"".to_string())),
Some("".to_string()))
.expect(&format!("failed to exec `{}`", config.adb_path));
2013-05-04 01:35:07 +00:00
if config.verbose {
println!("push ({}) {:?} {} {}",
config.target, file.display(),
copy_result.out, copy_result.err);
2013-05-04 01:35:07 +00:00
}
}
}
}
// codegen tests (vs. clang)
fn append_suffix_to_stem(p: &Path, suffix: &str) -> PathBuf {
if suffix.len() == 0 {
p.to_path_buf()
} else {
let mut stem = p.file_stem().unwrap().to_os_string();
stem.push_os_str(OsStr::from_str("-"));
stem.push_os_str(OsStr::from_str(suffix));
p.with_file_name(&stem)
}
}
2014-04-16 04:56:39 +00:00
fn compile_test_and_save_bitcode(config: &Config, props: &TestProps,
testfile: &Path) -> ProcRes {
let aux_dir = aux_output_dir_name(config, testfile);
// FIXME (#9639): This needs to handle non-utf8 paths
2014-09-17 19:56:31 +00:00
let mut link_args = vec!("-L".to_string(),
aux_dir.to_str().unwrap().to_string());
rustc: Start "stabilizing" some flags This commit shuffles around some CLI flags of the compiler to some more stable locations with some renamings. The changes made were: * The `-v` flag has been repurposes as the "verbose" flag. The version flag has been renamed to `-V`. * The `-h` screen has been split into two parts. Most top-level options (not all) show with `-h`, and the remaining options (generally obscure) can be shown with `--help -v` which is a "verbose help screen" * The `-V` flag (version flag now) has lost its argument as it is now requested with `rustc -vV` "verbose version". * The `--emit` option has had its `ir` and `bc` variants renamed to `llvm-ir` and `llvm-bc` to emphasize that they are LLVM's IR/bytecode. * The `--emit` option has grown a new variant, `dep-info`, which subsumes the `--dep-info` CLI argument. The `--dep-info` flag is now deprecated. * The `--parse-only`, `--no-trans`, and `--no-analysis` flags have moved behind the `-Z` family of flags. * The `--debuginfo` and `--opt-level` flags were moved behind the top-level `-C` flag. * The `--print-file-name` and `--print-crate-name` flags were moved behind one global `--print` flag which now accepts one of `crate-name`, `file-names`, or `sysroot`. This global `--print` flag is intended to serve as a mechanism for learning various metadata about the compiler itself. No warnings are currently enabled to allow tools like Cargo to have time to migrate to the new flags before spraying warnings to all users.
2014-12-16 00:03:39 +00:00
let llvm_args = vec!("--emit=llvm-bc,obj".to_string(),
"--crate-type=lib".to_string());
2014-09-17 19:56:31 +00:00
link_args.extend(llvm_args.into_iter());
let args = make_compile_args(config,
props,
2014-09-17 19:56:31 +00:00
link_args,
2014-11-21 18:50:44 +00:00
|a, b| TargetLocation::ThisDirectory(
output_base_name(a, b).parent()
.unwrap().to_path_buf()),
testfile);
compose_and_run_compiler(config, props, testfile, args, None)
}
2014-04-16 04:56:39 +00:00
fn compile_cc_with_clang_and_save_bitcode(config: &Config, _props: &TestProps,
testfile: &Path) -> ProcRes {
let bitcodefile = output_base_name(config, testfile).with_extension("bc");
let bitcodefile = append_suffix_to_stem(&bitcodefile, "clang");
let testcc = testfile.with_extension("cc");
let proc_args = ProcArgs {
// FIXME (#9639): This needs to handle non-utf8 paths
prog: config.clang_path.as_ref().unwrap().to_str().unwrap().to_string(),
args: vec!("-c".to_string(),
"-emit-llvm".to_string(),
"-o".to_string(),
bitcodefile.to_str().unwrap().to_string(),
testcc.to_str().unwrap().to_string())
};
compose_and_run(config, testfile, proc_args, Vec::new(), "", None, None)
}
2014-04-16 04:56:39 +00:00
fn extract_function_from_bitcode(config: &Config, _props: &TestProps,
fname: &str, testfile: &Path,
suffix: &str) -> ProcRes {
let bitcodefile = output_base_name(config, testfile).with_extension("bc");
let bitcodefile = append_suffix_to_stem(&bitcodefile, suffix);
let extracted_bc = append_suffix_to_stem(&bitcodefile, "extract");
2014-08-19 00:52:38 +00:00
let prog = config.llvm_bin_path.as_ref().unwrap().join("llvm-extract");
let proc_args = ProcArgs {
// FIXME (#9639): This needs to handle non-utf8 paths
prog: prog.to_str().unwrap().to_string(),
args: vec!(format!("-func={}", fname),
format!("-o={}", extracted_bc.to_str().unwrap()),
bitcodefile.to_str().unwrap().to_string())
};
compose_and_run(config, testfile, proc_args, Vec::new(), "", None, None)
}
2014-04-16 04:56:39 +00:00
fn disassemble_extract(config: &Config, _props: &TestProps,
testfile: &Path, suffix: &str) -> ProcRes {
let bitcodefile = output_base_name(config, testfile).with_extension("bc");
let bitcodefile = append_suffix_to_stem(&bitcodefile, suffix);
let extracted_bc = append_suffix_to_stem(&bitcodefile, "extract");
let extracted_ll = extracted_bc.with_extension("ll");
2014-08-19 00:52:38 +00:00
let prog = config.llvm_bin_path.as_ref().unwrap().join("llvm-dis");
let proc_args = ProcArgs {
// FIXME (#9639): This needs to handle non-utf8 paths
prog: prog.to_str().unwrap().to_string(),
args: vec!(format!("-o={}", extracted_ll.to_str().unwrap()),
extracted_bc.to_str().unwrap().to_string())
};
compose_and_run(config, testfile, proc_args, Vec::new(), "", None, None)
}
fn count_extracted_lines(p: &Path) -> uint {
let mut x = Vec::new();
File::open(&p.with_extension("ll")).unwrap().read_to_end(&mut x).unwrap();
let x = str::from_utf8(&x).unwrap();
x.lines().count()
}
2014-04-16 04:56:39 +00:00
fn run_codegen_test(config: &Config, props: &TestProps,
testfile: &Path, mm: &mut MetricMap) {
if config.llvm_bin_path.is_none() {
fatal("missing --llvm-bin-path");
}
if config.clang_path.is_none() {
fatal("missing --clang-path");
}
let mut proc_res = compile_test_and_save_bitcode(config, props, testfile);
if !proc_res.status.success() {
fatal_proc_rec("compilation failed!", &proc_res);
}
proc_res = extract_function_from_bitcode(config, props, "test", testfile, "");
if !proc_res.status.success() {
fatal_proc_rec("extracting 'test' function failed",
&proc_res);
}
proc_res = disassemble_extract(config, props, testfile, "");
if !proc_res.status.success() {
fatal_proc_rec("disassembling extract failed", &proc_res);
}
let mut proc_res = compile_cc_with_clang_and_save_bitcode(config, props, testfile);
if !proc_res.status.success() {
fatal_proc_rec("compilation failed!", &proc_res);
}
proc_res = extract_function_from_bitcode(config, props, "test", testfile, "clang");
if !proc_res.status.success() {
fatal_proc_rec("extracting 'test' function failed",
&proc_res);
}
proc_res = disassemble_extract(config, props, testfile, "clang");
if !proc_res.status.success() {
fatal_proc_rec("disassembling extract failed", &proc_res);
}
let base = output_base_name(config, testfile);
let base_extract = append_suffix_to_stem(&base, "extract");
let base_clang = append_suffix_to_stem(&base, "clang");
let base_clang_extract = append_suffix_to_stem(&base_clang, "extract");
let base_lines = count_extracted_lines(&base_extract);
let clang_lines = count_extracted_lines(&base_clang_extract);
mm.insert_metric("clang-codegen-ratio",
(base_lines as f64) / (clang_lines as f64),
0.001);
}