diff options
| author | bors <bors@rust-lang.org> | 2016-04-28 23:34:00 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2016-04-28 23:34:00 -0700 |
| commit | c0c08e2d77a4dab0414b08c4e9008113bf3fee67 (patch) | |
| tree | 3b7093d4ab4b5b41d21accd1a9e526629de41dab /src/tools | |
| parent | 8da2bcac5db1e091b90cceb19d0496f0f7501c88 (diff) | |
| parent | 126e09e5e5f0eeb7098188126e57169c3a622563 (diff) | |
| download | rust-c0c08e2d77a4dab0414b08c4e9008113bf3fee67.tar.gz rust-c0c08e2d77a4dab0414b08c4e9008113bf3fee67.zip | |
Auto merge of #33093 - alexcrichton:rustbuild-rmake, r=nikomatsakis
test: Move run-make tests into compiletest Forcing them to be embedded in makefiles precludes being able to run them in rustbuild, and adding them to compiletest gives us a great way to leverage future enhancements to our "all encompassing test suite runner" as well as just moving more things into Rust. All tests are still Makefile-based in the sense that they rely on `make` being available to run them, but there's no longer any Makefile-trickery to run them and rustbuild can now run them out of the box as well.
Diffstat (limited to 'src/tools')
| -rw-r--r-- | src/tools/compiletest/src/common.rs | 11 | ||||
| -rw-r--r-- | src/tools/compiletest/src/header.rs | 3 | ||||
| -rw-r--r-- | src/tools/compiletest/src/main.rs | 25 | ||||
| -rw-r--r-- | src/tools/compiletest/src/procsrv.rs | 14 | ||||
| -rw-r--r-- | src/tools/compiletest/src/runtest.rs | 117 |
5 files changed, 153 insertions, 17 deletions
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 81265f6ccaf..e7019de8f43 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -27,6 +27,7 @@ pub enum Mode { Rustdoc, CodegenUnits, Incremental, + RunMake, } impl FromStr for Mode { @@ -45,6 +46,7 @@ impl FromStr for Mode { "rustdoc" => Ok(Rustdoc), "codegen-units" => Ok(CodegenUnits), "incremental" => Ok(Incremental), + "run-make" => Ok(RunMake), _ => Err(()), } } @@ -65,6 +67,7 @@ impl fmt::Display for Mode { Rustdoc => "rustdoc", CodegenUnits => "codegen-units", Incremental => "incremental", + RunMake => "run-make", }, f) } } @@ -165,4 +168,12 @@ pub struct Config { // Print one character per test instead of one line pub quiet: bool, + + // Configuration for various run-make tests frobbing things like C compilers + // or querying about various LLVM component information. + pub cc: String, + pub cxx: String, + pub cflags: String, + pub llvm_components: String, + pub llvm_cxxflags: String, } diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index ef93fcfa013..c8df8739f52 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -291,6 +291,9 @@ pub fn early_props(config: &Config, testfile: &Path) -> EarlyProps { fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut FnMut(&str)) { + if testfile.is_dir() { + return + } let rdr = BufReader::new(File::open(testfile).unwrap()); for ln in rdr.lines() { // Assume that any directives will be found before the first diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index a9810099dbf..26382967c6b 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -35,7 +35,7 @@ use std::io; use std::path::{Path, PathBuf}; use getopts::{optopt, optflag, reqopt}; use common::Config; -use common::{Pretty, DebugInfoGdb, DebugInfoLldb}; +use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Mode}; use test::TestPaths; use util::logv; @@ -100,6 +100,11 @@ pub fn parse_config(args: Vec<String> ) -> Config { optopt("", "adb-path", "path to the android debugger", "PATH"), optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"), optopt("", "lldb-python-dir", "directory containing LLDB's python module", "PATH"), + reqopt("", "cc", "path to a C compiler", "PATH"), + reqopt("", "cxx", "path to a C++ compiler", "PATH"), + reqopt("", "cflags", "flags for the C compiler", "FLAGS"), + reqopt("", "llvm-components", "list of LLVM components built in", "LIST"), + reqopt("", "llvm-cxxflags", "C++ flags for LLVM", "FLAGS"), optflag("h", "help", "show this message")); let (argv0, args_) = args.split_first().unwrap(); @@ -175,6 +180,12 @@ pub fn parse_config(args: Vec<String> ) -> Config { lldb_python_dir: matches.opt_str("lldb-python-dir"), verbose: matches.opt_present("verbose"), quiet: matches.opt_present("quiet"), + + cc: matches.opt_str("cc").unwrap(), + cxx: matches.opt_str("cxx").unwrap(), + cflags: matches.opt_str("cflags").unwrap(), + llvm_components: matches.opt_str("llvm-components").unwrap(), + llvm_cxxflags: matches.opt_str("llvm-cxxflags").unwrap(), } } @@ -307,9 +318,19 @@ fn collect_tests_from_dir(config: &Config, // `compiletest-ignore-dir`. for file in fs::read_dir(dir)? { let file = file?; - if file.file_name() == *"compiletest-ignore-dir" { + let name = file.file_name(); + if name == *"compiletest-ignore-dir" { return Ok(()); } + if name == *"Makefile" && config.mode == Mode::RunMake { + let paths = TestPaths { + file: dir.to_path_buf(), + base: base.to_path_buf(), + relative_dir: relative_dir_path.parent().unwrap().to_path_buf(), + }; + tests.push(make_test(config, &paths)); + return Ok(()) + } } let dirs = fs::read_dir(dir)?; diff --git a/src/tools/compiletest/src/procsrv.rs b/src/tools/compiletest/src/procsrv.rs index f418edf6686..53b7cd059be 100644 --- a/src/tools/compiletest/src/procsrv.rs +++ b/src/tools/compiletest/src/procsrv.rs @@ -14,16 +14,20 @@ use std::io::prelude::*; use std::path::PathBuf; use std::process::{ExitStatus, Command, Child, Output, Stdio}; -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 = if cfg!(windows) { +pub fn dylib_env_var() -> &'static str { + if cfg!(windows) { "PATH" } else if cfg!(target_os = "macos") { "DYLD_LIBRARY_PATH" } else { "LD_LIBRARY_PATH" - }; + } +} + +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 { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index e0abf8200a0..fb296d57ebf 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -11,7 +11,7 @@ use common::Config; use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind}; use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc, CodegenUnits}; -use common::{Incremental}; +use common::{Incremental, RunMake}; use errors::{self, ErrorKind, Error}; use json; use header::TestProps; @@ -24,7 +24,7 @@ use std::env; use std::collections::HashSet; use std::fmt; use std::fs::{self, File}; -use std::io::BufReader; +use std::io::{self, BufReader}; use std::io::prelude::*; use std::net::TcpStream; use std::path::{Path, PathBuf}; @@ -62,6 +62,7 @@ pub fn run(config: Config, testpaths: &TestPaths) { Rustdoc => run_rustdoc_test(&config, &props, &testpaths), CodegenUnits => run_codegen_units_test(&config, &props, &testpaths), Incremental => run_incremental_test(&config, &props, &testpaths), + RunMake => run_rmake_test(&config, &props, &testpaths), } } @@ -1233,7 +1234,7 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps, testpaths: &TestPaths, args: ProcArgs, input: Option<String>) -> ProcRes { if !props.aux_builds.is_empty() { - ensure_dir(&aux_output_dir_name(config, testpaths)); + create_dir_racy(&aux_output_dir_name(config, testpaths)); } let aux_dir = aux_output_dir_name(config, testpaths); @@ -1307,11 +1308,6 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps, input) } -fn ensure_dir(path: &Path) { - if path.is_dir() { return; } - fs::create_dir_all(path).unwrap(); -} - fn compose_and_run(config: &Config, testpaths: &TestPaths, ProcArgs{ args, prog }: ProcArgs, @@ -1373,6 +1369,7 @@ fn make_compile_args<F>(config: &Config, DebugInfoLldb | Codegen | Rustdoc | + RunMake | CodegenUnits => { // do not use JSON output } @@ -1520,6 +1517,7 @@ fn make_cmdline(libpath: &str, prog: &str, args: &[String]) -> String { } fn dump_output(config: &Config, testpaths: &TestPaths, out: &str, err: &str) { + create_dir_racy(output_base_name(config, testpaths).parent().unwrap()); dump_output_file(config, testpaths, out, "out"); dump_output_file(config, testpaths, err, "err"); maybe_dump_to_stdout(config, out, err); @@ -1825,7 +1823,7 @@ fn run_rustdoc_test(config: &Config, props: &TestProps, testpaths: &TestPaths) { let out_dir = output_base_name(config, testpaths); let _ = fs::remove_dir_all(&out_dir); - ensure_dir(&out_dir); + create_dir_racy(&out_dir); let proc_res = document(config, props, testpaths, &out_dir); if !proc_res.status.success() { @@ -2029,7 +2027,7 @@ fn run_incremental_test(config: &Config, props: &TestProps, testpaths: &TestPath if incremental_dir.exists() { fs::remove_dir_all(&incremental_dir).unwrap(); } - fs::create_dir_all(&incremental_dir).unwrap(); + create_dir_racy(&incremental_dir); if config.verbose { print!("incremental_dir={}", incremental_dir.display()); @@ -2063,3 +2061,102 @@ fn run_incremental_test(config: &Config, props: &TestProps, testpaths: &TestPath } } } + +fn run_rmake_test(config: &Config, _props: &TestProps, testpaths: &TestPaths) { + let cwd = env::current_dir().unwrap(); + let src_root = config.src_base.parent().unwrap().parent().unwrap() + .parent().unwrap(); + let src_root = cwd.join(&src_root); + + let tmpdir = cwd.join(output_base_name(config, testpaths)); + if tmpdir.exists() { + aggressive_rm_rf(&tmpdir).unwrap(); + } + create_dir_racy(&tmpdir); + + let mut cmd = Command::new("make"); + cmd.current_dir(&testpaths.file) + .env("TARGET", &config.target) + .env("PYTHON", &config.docck_python) + .env("S", src_root) + .env("RUST_BUILD_STAGE", &config.stage_id) + .env("RUSTC", cwd.join(&config.rustc_path)) + .env("RUSTDOC", cwd.join(&config.rustdoc_path)) + .env("TMPDIR", &tmpdir) + .env("LD_LIB_PATH_ENVVAR", procsrv::dylib_env_var()) + .env("HOST_RPATH_DIR", cwd.join(&config.compile_lib_path)) + .env("TARGET_RPATH_DIR", cwd.join(&config.run_lib_path)) + .env("LLVM_COMPONENTS", &config.llvm_components) + .env("LLVM_CXXFLAGS", &config.llvm_cxxflags); + + if config.target.contains("msvc") { + // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` + // and that `lib.exe` lives next to it. + let lib = Path::new(&config.cc).parent().unwrap().join("lib.exe"); + + // MSYS doesn't like passing flags of the form `/foo` as it thinks it's + // a path and instead passes `C:\msys64\foo`, so convert all + // `/`-arguments to MSVC here to `-` arguments. + let cflags = config.cflags.split(' ').map(|s| s.replace("/", "-")) + .collect::<Vec<_>>().join(" "); + + cmd.env("IS_MSVC", "1") + .env("MSVC_LIB", format!("'{}' -nologo", lib.display())) + .env("CC", format!("'{}' {}", config.cc, cflags)) + .env("CXX", &config.cxx); + } else { + cmd.env("CC", format!("{} {}", config.cc, config.cflags)) + .env("CXX", format!("{} {}", config.cxx, config.cflags)); + } + + let output = cmd.output().expect("failed to spawn `make`"); + if !output.status.success() { + let res = ProcRes { + status: Status::Normal(output.status), + stdout: String::from_utf8_lossy(&output.stdout).into_owned(), + stderr: String::from_utf8_lossy(&output.stderr).into_owned(), + cmdline: format!("{:?}", cmd), + }; + fatal_proc_rec(None, "make failed", &res); + } +} + +fn aggressive_rm_rf(path: &Path) -> io::Result<()> { + for e in try!(path.read_dir()) { + let entry = try!(e); + let path = entry.path(); + if try!(entry.file_type()).is_dir() { + try!(aggressive_rm_rf(&path)); + } else { + // Remove readonly files as well on windows (by default we can't) + try!(fs::remove_file(&path).or_else(|e| { + if cfg!(windows) && e.kind() == io::ErrorKind::PermissionDenied { + let mut meta = try!(entry.metadata()).permissions(); + meta.set_readonly(false); + try!(fs::set_permissions(&path, meta)); + fs::remove_file(&path) + } else { + Err(e) + } + })) + } + } + fs::remove_dir(path) +} + +// Like std::fs::create_dir_all, except handles concurrent calls among multiple +// threads or processes. +fn create_dir_racy(path: &Path) { + match fs::create_dir(path) { + Ok(()) => return, + Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return, + Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} + Err(e) => panic!("failed to create dir {:?}: {}", path, e), + } + create_dir_racy(path.parent().unwrap()); + match fs::create_dir(path) { + Ok(()) => {} + Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => {} + Err(e) => panic!("failed to create dir {:?}: {}", path, e), + } +} |
