compiletest: remove legacy Makefile-based run-make support

This commit is contained in:
许杰友 Jieyou Xu (Joe) 2025-02-05 21:15:04 +08:00
parent 8c392966a0
commit 3998690a68
4 changed files with 18 additions and 214 deletions

View file

@ -709,11 +709,11 @@ impl TestProps {
/// returns a struct containing various parts of the directive.
fn line_directive<'line>(
line_number: usize,
comment: &str,
original_line: &'line str,
) -> Option<DirectiveLine<'line>> {
// Ignore lines that don't start with the comment prefix.
let after_comment = original_line.trim_start().strip_prefix(comment)?.trim_start();
let after_comment =
original_line.trim_start().strip_prefix(COMPILETEST_DIRECTIVE_PREFIX)?.trim_start();
let revision;
let raw_directive;
@ -722,7 +722,7 @@ fn line_directive<'line>(
// A comment like `//@[foo]` only applies to revision `foo`.
let Some((line_revision, after_close_bracket)) = after_open_bracket.split_once(']') else {
panic!(
"malformed condition directive: expected `{comment}[foo]`, found `{original_line}`"
"malformed condition directive: expected `{COMPILETEST_DIRECTIVE_PREFIX}[foo]`, found `{original_line}`"
)
};
@ -836,6 +836,8 @@ pub(crate) fn check_directive<'a>(
CheckDirectiveResult { is_known_directive: is_known(&directive_name), trailing_directive }
}
const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@";
fn iter_header(
mode: Mode,
_suite: &str,
@ -849,8 +851,7 @@ fn iter_header(
}
// Coverage tests in coverage-run mode always have these extra directives, without needing to
// specify them manually in every test file. (Some of the comments below have been copied over
// from the old `tests/run-make/coverage-reports/Makefile`, which no longer exists.)
// specify them manually in every test file.
//
// FIXME(jieyouxu): I feel like there's a better way to do this, leaving for later.
if mode == Mode::CoverageRun {
@ -867,9 +868,6 @@ fn iter_header(
}
}
// NOTE(jieyouxu): once we get rid of `Makefile`s we can unconditionally check for `//@`.
let comment = if testfile.extension().is_some_and(|e| e == "rs") { "//@" } else { "#" };
let mut rdr = BufReader::with_capacity(1024, rdr);
let mut ln = String::new();
let mut line_number = 0;
@ -882,7 +880,7 @@ fn iter_header(
}
let ln = ln.trim();
let Some(directive_line) = line_directive(line_number, comment, ln) else {
let Some(directive_line) = line_directive(line_number, ln) else {
continue;
};

View file

@ -239,11 +239,6 @@ fn check_ignore(config: &Config, contents: &str) -> bool {
d.ignore
}
fn parse_makefile(config: &Config, contents: &str) -> EarlyProps {
let bytes = contents.as_bytes();
EarlyProps::from_reader(config, Path::new("Makefile"), bytes)
}
#[test]
fn should_fail() {
let config: Config = cfg().build();
@ -261,10 +256,6 @@ fn revisions() {
let config: Config = cfg().build();
assert_eq!(parse_rs(&config, "//@ revisions: a b c").revisions, vec!["a", "b", "c"],);
assert_eq!(
parse_makefile(&config, "# revisions: hello there").revisions,
vec!["hello", "there"],
);
}
#[test]

View file

@ -21,7 +21,7 @@ pub mod util;
use core::panic;
use std::collections::HashSet;
use std::ffi::{OsStr, OsString};
use std::ffi::OsString;
use std::io::{self, ErrorKind};
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
@ -268,12 +268,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
let path = Path::new(f);
let mut iter = path.iter().skip(1);
// We skip the test folder and check if the user passed `rmake.rs` or `Makefile`.
if iter
.next()
.is_some_and(|s| s == OsStr::new("rmake.rs") || s == OsStr::new("Makefile"))
&& iter.next().is_none()
{
// We skip the test folder and check if the user passed `rmake.rs`.
if iter.next().is_some_and(|s| s == "rmake.rs") && iter.next().is_none() {
path.parent().unwrap().to_str().unwrap().to_string()
} else {
f.to_string()
@ -776,16 +772,9 @@ fn collect_tests_from_dir(
return Ok(());
}
// For run-make tests, a "test file" is actually a directory that contains
// an `rmake.rs` or `Makefile`"
// For run-make tests, a "test file" is actually a directory that contains an `rmake.rs`.
if cx.config.mode == Mode::RunMake {
if dir.join("Makefile").exists() && dir.join("rmake.rs").exists() {
return Err(io::Error::other(
"run-make tests cannot have both `Makefile` and `rmake.rs`",
));
}
if dir.join("Makefile").exists() || dir.join("rmake.rs").exists() {
if dir.join("rmake.rs").exists() {
let paths = TestPaths {
file: dir.to_path_buf(),
relative_dir: relative_dir_path.parent().unwrap().to_path_buf(),
@ -854,24 +843,14 @@ pub fn is_test(file_name: &OsString) -> bool {
!invalid_prefixes.iter().any(|p| file_name.starts_with(p))
}
/// For a single test file, creates one or more test structures (one per revision)
/// that can be handed over to libtest to run, possibly in parallel.
/// For a single test file, creates one or more test structures (one per revision) that can be
/// handed over to libtest to run, possibly in parallel.
fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &TestPaths) {
// For run-make tests, each "test file" is actually a _directory_ containing
// an `rmake.rs` or `Makefile`. But for the purposes of directive parsing,
// we want to look at that recipe file, not the directory itself.
// For run-make tests, each "test file" is actually a _directory_ containing an `rmake.rs`. But
// for the purposes of directive parsing, we want to look at that recipe file, not the directory
// itself.
let test_path = if cx.config.mode == Mode::RunMake {
if testpaths.file.join("rmake.rs").exists() && testpaths.file.join("Makefile").exists() {
panic!("run-make tests cannot have both `rmake.rs` and `Makefile`");
}
if testpaths.file.join("rmake.rs").exists() {
// Parse directives in rmake.rs.
testpaths.file.join("rmake.rs")
} else {
// Parse directives in the Makefile.
testpaths.file.join("Makefile")
}
testpaths.file.join("rmake.rs")
} else {
PathBuf::from(&testpaths.file)
};

View file

@ -9,168 +9,6 @@ use crate::util::{copy_dir_all, dylib_env_var};
impl TestCx<'_> {
pub(super) fn run_rmake_test(&self) {
let test_dir = &self.testpaths.file;
if test_dir.join("rmake.rs").exists() {
self.run_rmake_v2_test();
} else if test_dir.join("Makefile").exists() {
self.run_rmake_legacy_test();
} else {
self.fatal("failed to find either `rmake.rs` or `Makefile`")
}
}
fn run_rmake_legacy_test(&self) {
let cwd = env::current_dir().unwrap();
// FIXME(Zalathar): This should probably be `output_base_dir` to avoid
// an unnecessary extra subdirectory, but since legacy Makefile tests
// are hopefully going away, it seems safer to leave this perilous code
// as-is until it can all be deleted.
let tmpdir = cwd.join(self.output_base_name());
ignore_not_found(|| recursive_remove(&tmpdir)).unwrap();
fs::create_dir_all(&tmpdir).unwrap();
let host = &self.config.host;
let make = if host.contains("dragonfly")
|| host.contains("freebsd")
|| host.contains("netbsd")
|| host.contains("openbsd")
|| host.contains("aix")
{
"gmake"
} else {
"make"
};
let mut cmd = Command::new(make);
cmd.current_dir(&self.testpaths.file)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.env("TARGET", &self.config.target)
.env("PYTHON", &self.config.python)
.env("S", &self.config.src_root)
.env("RUST_BUILD_STAGE", &self.config.stage_id)
.env("RUSTC", cwd.join(&self.config.rustc_path))
.env("TMPDIR", &tmpdir)
.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)
// We for sure don't want these tests to run in parallel, so make
// sure they don't have access to these vars if we run via `make`
// at the top level
.env_remove("MAKEFLAGS")
.env_remove("MFLAGS")
.env_remove("CARGO_MAKEFLAGS");
if let Some(ref cargo) = self.config.cargo_path {
cmd.env("CARGO", cwd.join(cargo));
}
if let Some(ref rustdoc) = self.config.rustdoc_path {
cmd.env("RUSTDOC", cwd.join(rustdoc));
}
if let Some(ref node) = self.config.nodejs {
cmd.env("NODE", node);
}
if let Some(ref linker) = self.config.target_linker {
cmd.env("RUSTC_LINKER", linker);
}
if let Some(ref clang) = self.config.run_clang_based_tests_with {
cmd.env("CLANG", clang);
}
if let Some(ref filecheck) = self.config.llvm_filecheck {
cmd.env("LLVM_FILECHECK", filecheck);
}
if let Some(ref llvm_bin_dir) = self.config.llvm_bin_dir {
cmd.env("LLVM_BIN_DIR", llvm_bin_dir);
}
if let Some(ref remote_test_client) = self.config.remote_test_client {
cmd.env("REMOTE_TEST_CLIENT", remote_test_client);
}
// We don't want RUSTFLAGS set from the outside to interfere with
// compiler flags set in the test cases:
cmd.env_remove("RUSTFLAGS");
// Use dynamic musl for tests because static doesn't allow creating dylibs
if self.config.host.contains("musl") {
cmd.env("RUSTFLAGS", "-Ctarget-feature=-crt-static").env("IS_MUSL_HOST", "1");
}
if self.config.bless {
cmd.env("RUSTC_BLESS_TEST", "--bless");
// Assume this option is active if the environment variable is "defined", with _any_ value.
// As an example, a `Makefile` can use this option by:
//
// ifdef RUSTC_BLESS_TEST
// cp "$(TMPDIR)"/actual_something.ext expected_something.ext
// else
// $(DIFF) expected_something.ext "$(TMPDIR)"/actual_something.ext
// endif
}
if self.config.target.contains("msvc") && !self.config.cc.is_empty() {
// 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(&self.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 = self
.config
.cflags
.split(' ')
.map(|s| s.replace("/", "-"))
.collect::<Vec<_>>()
.join(" ");
let cxxflags = self
.config
.cxxflags
.split(' ')
.map(|s| s.replace("/", "-"))
.collect::<Vec<_>>()
.join(" ");
cmd.env("IS_MSVC", "1")
.env("IS_WINDOWS", "1")
.env("MSVC_LIB", format!("'{}' -nologo", lib.display()))
.env("MSVC_LIB_PATH", format!("{}", lib.display()))
.env("CC", format!("'{}' {}", self.config.cc, cflags))
.env("CXX", format!("'{}' {}", &self.config.cxx, cxxflags));
} else {
cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags))
.env("CXX", format!("{} {}", self.config.cxx, self.config.cxxflags))
.env("AR", &self.config.ar);
if self.config.target.contains("windows") {
cmd.env("IS_WINDOWS", "1");
}
}
let (output, truncated) =
self.read2_abbreviated(cmd.spawn().expect("failed to spawn `make`"));
if !output.status.success() {
let res = ProcRes {
status: output.status,
stdout: String::from_utf8_lossy(&output.stdout).into_owned(),
stderr: String::from_utf8_lossy(&output.stderr).into_owned(),
truncated,
cmdline: format!("{:?}", cmd),
};
self.fatal_proc_rec("make failed", &res);
}
}
fn run_rmake_v2_test(&self) {
// For `run-make` V2, we need to perform 2 steps to build and run a `run-make` V2 recipe
// (`rmake.rs`) to run the actual tests. The support library is already built as a tool rust
// library and is available under `build/$TARGET/stageN-tools-bin/librun_make_support.rlib`.
@ -191,8 +29,6 @@ impl TestCx<'_> {
// recipes to `remove_dir_all($TMPDIR)` without running into issues related trying to remove
// a currently running executable because the recipe executable is not under the
// `rmake_out/` directory.
//
// This setup intentionally diverges from legacy Makefile run-make tests.
let base_dir = self.output_base_dir();
ignore_not_found(|| recursive_remove(&base_dir)).unwrap();