Auto merge of #126097 - Kobzol:runmake-change-cwd, r=jieyouxu

Change how runmake v2 tests are executed

This PR makes execution of v2 runmake tests more sane, by executing each test in a temporary directory by default, rather than running it inside `tests/run-make`. This will have.. a lot of conflicts.

Fixes: https://github.com/rust-lang/rust/issues/126080
Closes https://github.com/rust-lang/rust/issues/125726, because it removes `tmp_dir`, lol.

r? `@jieyouxu`

try-job: x86_64-msvc
This commit is contained in:
bors 2024-06-08 15:25:05 +00:00
commit cfdb6175c2
74 changed files with 275 additions and 302 deletions

View file

@ -15,7 +15,7 @@ use crate::errors::{self, Error, ErrorKind};
use crate::header::TestProps;
use crate::json;
use crate::read2::{read2_abbreviated, Truncated};
use crate::util::{add_dylib_path, dylib_env_var, logv, PathBufExt};
use crate::util::{add_dylib_path, copy_dir_all, dylib_env_var, logv, PathBufExt};
use crate::ColorConfig;
use colored::Colorize;
use miropt_test_tools::{files_for_miropt_test, MiroptTest, MiroptTestFile};
@ -3471,6 +3471,21 @@ impl<'test> TestCx<'test> {
let rmake_out_dir = base_dir.join("rmake_out");
create_dir_all(&rmake_out_dir).unwrap();
// Copy all input files (apart from rmake.rs) to the temporary directory,
// so that the input directory structure from `tests/run-make/<test>` is mirrored
// to the `rmake_out` directory.
for path in walkdir::WalkDir::new(&self.testpaths.file).min_depth(1) {
let path = path.unwrap().path().to_path_buf();
if path.file_name().is_some_and(|s| s != "rmake.rs") {
let target = rmake_out_dir.join(path.strip_prefix(&self.testpaths.file).unwrap());
if path.is_dir() {
copy_dir_all(&path, target).unwrap();
} else {
fs::copy(&path, target).unwrap();
}
}
}
// HACK: assume stageN-target, we only want stageN.
let stage = self.config.stage_id.split('-').next().unwrap();
@ -3530,18 +3545,11 @@ impl<'test> TestCx<'test> {
.env("PYTHON", &self.config.python)
.env("RUST_BUILD_STAGE", &self.config.stage_id)
.env("RUSTC", cwd.join(&self.config.rustc_path))
.env("TMPDIR", &rmake_out_dir)
.env("LD_LIB_PATH_ENVVAR", dylib_env_var())
.env(dylib_env_var(), &host_dylib_env_paths)
.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");
.env("LLVM_COMPONENTS", &self.config.llvm_components);
if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() {
let mut stage0_sysroot = build_root.clone();
@ -3571,7 +3579,7 @@ impl<'test> TestCx<'test> {
let target_rpath_env_path = env::join_paths(target_rpath_env_path).unwrap();
let mut cmd = Command::new(&recipe_bin);
cmd.current_dir(&self.testpaths.file)
cmd.current_dir(&rmake_out_dir)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.env("LD_LIB_PATH_ENVVAR", dylib_env_var())
@ -3582,16 +3590,9 @@ impl<'test> TestCx<'test> {
.env("SOURCE_ROOT", &src_root)
.env("RUST_BUILD_STAGE", &self.config.stage_id)
.env("RUSTC", cwd.join(&self.config.rustc_path))
.env("TMPDIR", &rmake_out_dir)
.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");
.env("LLVM_COMPONENTS", &self.config.llvm_components);
if let Some(ref rustdoc) = self.config.rustdoc_path {
cmd.env("RUSTDOC", cwd.join(rustdoc));

View file

@ -1,7 +1,7 @@
use crate::common::Config;
use std::env;
use std::ffi::OsStr;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::process::Command;
use tracing::*;
@ -76,3 +76,17 @@ pub fn add_dylib_path(cmd: &mut Command, paths: impl Iterator<Item = impl Into<P
let new_paths = paths.map(Into::into).chain(old_paths.into_iter().flatten());
cmd.env(dylib_env_var(), env::join_paths(new_paths).unwrap());
}
pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> std::io::Result<()> {
std::fs::create_dir_all(&dst)?;
for entry in std::fs::read_dir(src)? {
let entry = entry?;
let ty = entry.file_type()?;
if ty.is_dir() {
copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
} else {
std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
}
}
Ok(())
}

View file

@ -1,9 +1,7 @@
use std::path::Path;
use std::process::Command;
use crate::{
bin_name, cygpath_windows, env_var, handle_failed_output, is_msvc, is_windows, tmp_dir, uname,
};
use crate::{bin_name, cygpath_windows, env_var, handle_failed_output, is_msvc, is_windows, uname};
/// Construct a new platform-specific C compiler invocation.
///
@ -54,8 +52,7 @@ impl Cc {
self
}
/// Specify `-o` or `-Fe`/`-Fo` depending on platform/compiler. This assumes that the executable
/// is under `$TMPDIR`.
/// Specify `-o` or `-Fe`/`-Fo` depending on platform/compiler.
pub fn out_exe(&mut self, name: &str) -> &mut Self {
// Ref: tools.mk (irrelevant lines omitted):
//
@ -69,13 +66,13 @@ impl Cc {
// ```
if is_msvc() {
let fe_path = cygpath_windows(tmp_dir().join(bin_name(name)));
let fo_path = cygpath_windows(tmp_dir().join(format!("{name}.obj")));
let fe_path = cygpath_windows(bin_name(name));
let fo_path = cygpath_windows(format!("{name}.obj"));
self.cmd.arg(format!("-Fe:{fe_path}"));
self.cmd.arg(format!("-Fo:{fo_path}"));
} else {
self.cmd.arg("-o");
self.cmd.arg(tmp_dir().join(name));
self.cmd.arg(name);
}
self

View file

@ -1,7 +1,7 @@
use std::path::Path;
use std::process::Command;
use crate::{bin_name, env_var, handle_failed_output, tmp_dir};
use crate::{bin_name, env_var, handle_failed_output};
/// Construct a new `clang` invocation. `clang` is not always available for all targets.
pub fn clang() -> Clang {
@ -30,11 +30,11 @@ impl Clang {
self
}
/// Specify the name of the executable. The executable will be placed under `$TMPDIR`, and the
/// extension will be determined by [`bin_name`].
/// Specify the name of the executable. The executable will be placed under the current directory
/// and the extension will be determined by [`bin_name`].
pub fn out_exe(&mut self, name: &str) -> &mut Self {
self.cmd.arg("-o");
self.cmd.arg(tmp_dir().join(bin_name(name)));
self.cmd.arg(bin_name(name));
self
}

View file

@ -45,11 +45,6 @@ pub fn env_var_os(name: &str) -> OsString {
}
}
/// Path of `TMPDIR` (a temporary build directory, not under `/tmp`).
pub fn tmp_dir() -> PathBuf {
env_var_os("TMPDIR").into()
}
/// `TARGET`
pub fn target() -> String {
env_var("TARGET")
@ -70,12 +65,6 @@ pub fn is_darwin() -> bool {
target().contains("darwin")
}
/// Construct a path to a static library under `$TMPDIR` given the library name. This will return a
/// path with `$TMPDIR` joined with platform-and-compiler-specific library name.
pub fn static_lib(name: &str) -> PathBuf {
tmp_dir().join(static_lib_name(name))
}
pub fn python_command() -> Command {
let python_path = env_var("PYTHON");
Command::new(python_path)
@ -116,12 +105,6 @@ pub fn static_lib_name(name: &str) -> String {
if is_msvc() { format!("{name}.lib") } else { format!("lib{name}.a") }
}
/// Construct a path to a dynamic library under `$TMPDIR` given the library name. This will return a
/// path with `$TMPDIR` joined with platform-and-compiler-specific library name.
pub fn dynamic_lib(name: &str) -> PathBuf {
tmp_dir().join(dynamic_lib_name(name))
}
/// Construct the dynamic library name based on the platform.
pub fn dynamic_lib_name(name: &str) -> String {
// See tools.mk (irrelevant lines omitted):
@ -159,14 +142,7 @@ pub fn dynamic_lib_extension() -> &'static str {
}
}
/// Construct a path to a rust library (rlib) under `$TMPDIR` given the library name. This will return a
/// path with `$TMPDIR` joined with the library name.
pub fn rust_lib(name: &str) -> PathBuf {
tmp_dir().join(rust_lib_name(name))
}
/// Generate the name a rust library (rlib) would have. If you want the complete path, use
/// [`rust_lib`] instead.
/// Construct a rust library (rlib) name.
pub fn rust_lib_name(name: &str) -> String {
format!("lib{name}.rlib")
}
@ -176,6 +152,11 @@ pub fn bin_name(name: &str) -> String {
if is_windows() { format!("{name}.exe") } else { name.to_string() }
}
/// Return the current working directory.
pub fn cwd() -> PathBuf {
env::current_dir().unwrap()
}
/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is
/// available on the platform!
#[track_caller]
@ -227,7 +208,7 @@ pub fn set_host_rpath(cmd: &mut Command) {
let ld_lib_path_envvar = env_var("LD_LIB_PATH_ENVVAR");
cmd.env(&ld_lib_path_envvar, {
let mut paths = vec![];
paths.push(PathBuf::from(env_var("TMPDIR")));
paths.push(cwd());
paths.push(PathBuf::from(env_var("HOST_RPATH_DIR")));
for p in env::split_paths(&env_var(&ld_lib_path_envvar)) {
paths.push(p.to_path_buf());
@ -315,6 +296,27 @@ pub fn assert_not_contains(haystack: &str, needle: &str) {
}
}
/// This function is designed for running commands in a temporary directory
/// that is cleared after the function ends.
///
/// What this function does:
/// 1) Creates a temporary directory (`tmpdir`)
/// 2) Copies all files from the current directory to `tmpdir`
/// 3) Changes the current working directory to `tmpdir`
/// 4) Calls `callback`
/// 5) Switches working directory back to the original one
/// 6) Removes `tmpdir`
pub fn run_in_tmpdir<F: FnOnce()>(callback: F) {
let original_dir = cwd();
let tmpdir = original_dir.join("../temporary-directory");
copy_dir_all(".", &tmpdir);
env::set_current_dir(&tmpdir).unwrap();
callback();
env::set_current_dir(original_dir).unwrap();
fs::remove_dir_all(tmpdir).unwrap();
}
/// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct
/// containing a `cmd: Command` field and a `output` function. The provided helpers are:
///

View file

@ -2,19 +2,19 @@ use std::env;
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
use crate::{env_var, is_windows};
use crate::{cwd, env_var, is_windows};
use super::handle_failed_output;
fn run_common(name: &str) -> (Command, Output) {
let mut bin_path = PathBuf::new();
bin_path.push(env_var("TMPDIR"));
bin_path.push(cwd());
bin_path.push(name);
let ld_lib_path_envvar = env_var("LD_LIB_PATH_ENVVAR");
let mut cmd = Command::new(bin_path);
cmd.env(&ld_lib_path_envvar, {
let mut paths = vec![];
paths.push(PathBuf::from(env_var("TMPDIR")));
paths.push(cwd());
for p in env::split_paths(&env_var("TARGET_RPATH_ENV")) {
paths.push(p.to_path_buf());
}

View file

@ -3,7 +3,7 @@ use std::io::Write;
use std::path::Path;
use std::process::{Command, Output, Stdio};
use crate::{env_var, handle_failed_output, set_host_rpath, tmp_dir};
use crate::{cwd, env_var, handle_failed_output, set_host_rpath};
/// Construct a new `rustc` invocation.
pub fn rustc() -> Rustc {
@ -28,7 +28,7 @@ fn setup_common() -> Command {
let rustc = env_var("RUSTC");
let mut cmd = Command::new(rustc);
set_host_rpath(&mut cmd);
cmd.arg("--out-dir").arg(tmp_dir()).arg("-L").arg(tmp_dir());
cmd.arg("-L").arg(cwd());
cmd
}