Add supporting infrastructure for run-make
V2 tests
This commit is contained in:
parent
d3d145ea1c
commit
48e9f92ce2
@ -3274,6 +3274,10 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "run_make_support"
|
||||||
|
version = "0.0.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-demangler"
|
name = "rust-demangler"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
@ -10,6 +10,7 @@ members = [
|
|||||||
"src/tools/clippy",
|
"src/tools/clippy",
|
||||||
"src/tools/clippy/clippy_dev",
|
"src/tools/clippy/clippy_dev",
|
||||||
"src/tools/compiletest",
|
"src/tools/compiletest",
|
||||||
|
"src/tools/run-make-support",
|
||||||
"src/tools/error_index_generator",
|
"src/tools/error_index_generator",
|
||||||
"src/tools/linkchecker",
|
"src/tools/linkchecker",
|
||||||
"src/tools/lint-docs",
|
"src/tools/lint-docs",
|
||||||
|
@ -1327,6 +1327,52 @@ fn run(self, builder: &Builder<'_>) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
|
||||||
|
pub struct RunMakeSupport {
|
||||||
|
pub compiler: Compiler,
|
||||||
|
pub target: TargetSelection,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Step for RunMakeSupport {
|
||||||
|
type Output = PathBuf;
|
||||||
|
const DEFAULT: bool = true;
|
||||||
|
|
||||||
|
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||||
|
run.never()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_run(run: RunConfig<'_>) {
|
||||||
|
let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
|
||||||
|
run.builder.ensure(RunMakeSupport { compiler, target: run.build_triple() });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(self, builder: &Builder<'_>) -> PathBuf {
|
||||||
|
builder.ensure(compile::Std::new(self.compiler, self.target));
|
||||||
|
|
||||||
|
let cargo = tool::prepare_tool_cargo(
|
||||||
|
builder,
|
||||||
|
self.compiler,
|
||||||
|
Mode::ToolStd,
|
||||||
|
self.target,
|
||||||
|
"build",
|
||||||
|
"src/tools/run-make-support",
|
||||||
|
SourceType::InTree,
|
||||||
|
&[],
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut cargo = Command::from(cargo);
|
||||||
|
builder.run(&mut cargo);
|
||||||
|
|
||||||
|
let lib_name = "librun_make_support.rlib";
|
||||||
|
let lib = builder.tools_dir(self.compiler).join(&lib_name);
|
||||||
|
|
||||||
|
let cargo_out =
|
||||||
|
builder.cargo_out(self.compiler, Mode::ToolStd, self.target).join(&lib_name);
|
||||||
|
builder.copy(&cargo_out, &lib);
|
||||||
|
lib
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
default_test!(Ui { path: "tests/ui", mode: "ui", suite: "ui" });
|
default_test!(Ui { path: "tests/ui", mode: "ui", suite: "ui" });
|
||||||
|
|
||||||
default_test!(RunPassValgrind {
|
default_test!(RunPassValgrind {
|
||||||
@ -1361,7 +1407,40 @@ fn run(self, builder: &Builder<'_>) {
|
|||||||
|
|
||||||
host_test!(Pretty { path: "tests/pretty", mode: "pretty", suite: "pretty" });
|
host_test!(Pretty { path: "tests/pretty", mode: "pretty", suite: "pretty" });
|
||||||
|
|
||||||
default_test!(RunMake { path: "tests/run-make", mode: "run-make", suite: "run-make" });
|
// Special-handling is needed for `run-make`, so don't use `default_test` for defining `RunMake`
|
||||||
|
// tests.
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct RunMake {
|
||||||
|
pub compiler: Compiler,
|
||||||
|
pub target: TargetSelection,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Step for RunMake {
|
||||||
|
type Output = ();
|
||||||
|
const DEFAULT: bool = true;
|
||||||
|
const ONLY_HOSTS: bool = false;
|
||||||
|
|
||||||
|
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||||
|
run.suite_path("tests/run-make")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_run(run: RunConfig<'_>) {
|
||||||
|
let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
|
||||||
|
run.builder.ensure(RunMakeSupport { compiler, target: run.build_triple() });
|
||||||
|
run.builder.ensure(RunMake { compiler, target: run.target });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(self, builder: &Builder<'_>) {
|
||||||
|
builder.ensure(Compiletest {
|
||||||
|
compiler: self.compiler,
|
||||||
|
target: self.target,
|
||||||
|
mode: "run-make",
|
||||||
|
suite: "run-make",
|
||||||
|
path: "tests/run-make",
|
||||||
|
compare_mode: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
host_test!(RunMakeFullDeps {
|
host_test!(RunMakeFullDeps {
|
||||||
path: "tests/run-make-fulldeps",
|
path: "tests/run-make-fulldeps",
|
||||||
|
@ -655,13 +655,21 @@ fn collect_tests_from_dir(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.mode == Mode::RunMake && dir.join("Makefile").exists() {
|
if config.mode == Mode::RunMake {
|
||||||
let paths = TestPaths {
|
if dir.join("Makefile").exists() && dir.join("rmake.rs").exists() {
|
||||||
file: dir.to_path_buf(),
|
return Err(io::Error::other(
|
||||||
relative_dir: relative_dir_path.parent().unwrap().to_path_buf(),
|
"run-make tests cannot have both `Makefile` and `rmake.rs`",
|
||||||
};
|
));
|
||||||
tests.extend(make_test(config, cache, &paths, inputs, poisoned));
|
}
|
||||||
return Ok(());
|
|
||||||
|
if dir.join("Makefile").exists() || dir.join("rmake.rs").exists() {
|
||||||
|
let paths = TestPaths {
|
||||||
|
file: dir.to_path_buf(),
|
||||||
|
relative_dir: relative_dir_path.parent().unwrap().to_path_buf(),
|
||||||
|
};
|
||||||
|
tests.extend(make_test(config, cache, &paths, inputs, poisoned));
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we find a test foo/bar.rs, we have to build the
|
// If we find a test foo/bar.rs, we have to build the
|
||||||
@ -733,8 +741,17 @@ fn make_test(
|
|||||||
poisoned: &mut bool,
|
poisoned: &mut bool,
|
||||||
) -> Vec<test::TestDescAndFn> {
|
) -> Vec<test::TestDescAndFn> {
|
||||||
let test_path = if config.mode == Mode::RunMake {
|
let test_path = if config.mode == Mode::RunMake {
|
||||||
// Parse directives in the Makefile
|
if testpaths.file.join("rmake.rs").exists() && testpaths.file.join("Makefile").exists() {
|
||||||
testpaths.file.join("Makefile")
|
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")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
PathBuf::from(&testpaths.file)
|
PathBuf::from(&testpaths.file)
|
||||||
};
|
};
|
||||||
|
@ -3570,6 +3570,17 @@ fn run_incremental_test(&self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run_rmake_test(&self) {
|
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();
|
let cwd = env::current_dir().unwrap();
|
||||||
let src_root = self.config.src_base.parent().unwrap().parent().unwrap();
|
let src_root = self.config.src_base.parent().unwrap().parent().unwrap();
|
||||||
let src_root = cwd.join(&src_root);
|
let src_root = cwd.join(&src_root);
|
||||||
@ -3737,6 +3748,238 @@ fn aggressive_rm_rf(&self, path: &Path) -> io::Result<()> {
|
|||||||
fs::remove_dir(path)
|
fs::remove_dir(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
// dylib and is available under `build/$TARGET/stageN-tools-bin/librun_make_support.rlib`.
|
||||||
|
//
|
||||||
|
// 1. We need to build the recipe `rmake.rs` and link in the support library.
|
||||||
|
// 2. We need to run the recipe to build and run the tests.
|
||||||
|
let cwd = env::current_dir().unwrap();
|
||||||
|
let src_root = self.config.src_base.parent().unwrap().parent().unwrap();
|
||||||
|
let src_root = cwd.join(&src_root);
|
||||||
|
let build_root = self.config.build_base.parent().unwrap().parent().unwrap();
|
||||||
|
let build_root = cwd.join(&build_root);
|
||||||
|
|
||||||
|
let tmpdir = cwd.join(self.output_base_name());
|
||||||
|
if tmpdir.exists() {
|
||||||
|
self.aggressive_rm_rf(&tmpdir).unwrap();
|
||||||
|
}
|
||||||
|
create_dir_all(&tmpdir).unwrap();
|
||||||
|
|
||||||
|
// HACK: assume stageN-target, we only want stageN.
|
||||||
|
let stage = self.config.stage_id.split('-').next().unwrap();
|
||||||
|
|
||||||
|
// First, we construct the path to the built support library.
|
||||||
|
let mut support_lib_path = PathBuf::new();
|
||||||
|
support_lib_path.push(&build_root);
|
||||||
|
support_lib_path.push(format!("{}-tools-bin", stage));
|
||||||
|
support_lib_path.push("librun_make_support.rlib");
|
||||||
|
|
||||||
|
let mut stage_std_path = PathBuf::new();
|
||||||
|
stage_std_path.push(&build_root);
|
||||||
|
stage_std_path.push(&stage);
|
||||||
|
stage_std_path.push("lib");
|
||||||
|
|
||||||
|
// Then, we need to build the recipe `rmake.rs` and link in the support library.
|
||||||
|
let recipe_bin =
|
||||||
|
tmpdir.join(if self.config.target.contains("windows") { "rmake.exe" } else { "rmake" });
|
||||||
|
|
||||||
|
let mut support_lib_deps = PathBuf::new();
|
||||||
|
support_lib_deps.push(&build_root);
|
||||||
|
support_lib_deps.push(format!("{}-tools", stage));
|
||||||
|
support_lib_deps.push(&self.config.host);
|
||||||
|
support_lib_deps.push("release");
|
||||||
|
support_lib_deps.push("deps");
|
||||||
|
|
||||||
|
let mut support_lib_deps_deps = PathBuf::new();
|
||||||
|
support_lib_deps_deps.push(&build_root);
|
||||||
|
support_lib_deps_deps.push(format!("{}-tools", stage));
|
||||||
|
support_lib_deps_deps.push("release");
|
||||||
|
support_lib_deps_deps.push("deps");
|
||||||
|
|
||||||
|
debug!(?support_lib_deps);
|
||||||
|
debug!(?support_lib_deps_deps);
|
||||||
|
|
||||||
|
let res = self.cmd2procres(
|
||||||
|
Command::new(&self.config.rustc_path)
|
||||||
|
.arg("-o")
|
||||||
|
.arg(&recipe_bin)
|
||||||
|
.arg(format!(
|
||||||
|
"-Ldependency={}",
|
||||||
|
&support_lib_path.parent().unwrap().to_string_lossy()
|
||||||
|
))
|
||||||
|
.arg(format!("-Ldependency={}", &support_lib_deps.to_string_lossy()))
|
||||||
|
.arg(format!("-Ldependency={}", &support_lib_deps_deps.to_string_lossy()))
|
||||||
|
.arg("--extern")
|
||||||
|
.arg(format!("run_make_support={}", &support_lib_path.to_string_lossy()))
|
||||||
|
.arg(&self.testpaths.file.join("rmake.rs"))
|
||||||
|
.env("TARGET", &self.config.target)
|
||||||
|
.env("PYTHON", &self.config.python)
|
||||||
|
.env("S", &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 !res.status.success() {
|
||||||
|
self.fatal_proc_rec("run-make test failed: could not build `rmake.rs` recipe", &res);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, we need to run the recipe binary to build and run the actual tests.
|
||||||
|
debug!(?recipe_bin);
|
||||||
|
|
||||||
|
let mut dylib_env_paths = String::new();
|
||||||
|
dylib_env_paths.push_str(&env::var(dylib_env_var()).unwrap());
|
||||||
|
dylib_env_paths.push(':');
|
||||||
|
dylib_env_paths.push_str(&support_lib_path.parent().unwrap().to_string_lossy());
|
||||||
|
dylib_env_paths.push(':');
|
||||||
|
dylib_env_paths.push_str(
|
||||||
|
&stage_std_path.join("rustlib").join(&self.config.host).join("lib").to_string_lossy(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut target_rpath_env_path = String::new();
|
||||||
|
target_rpath_env_path.push_str(&tmpdir.to_string_lossy());
|
||||||
|
target_rpath_env_path.push(':');
|
||||||
|
target_rpath_env_path.push_str(&dylib_env_paths);
|
||||||
|
|
||||||
|
let mut cmd = Command::new(&recipe_bin);
|
||||||
|
cmd.current_dir(&self.testpaths.file)
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.env("LD_LIB_PATH_ENVVAR", dylib_env_var())
|
||||||
|
.env("TARGET_RPATH_ENV", &target_rpath_env_path)
|
||||||
|
.env(dylib_env_var(), &dylib_env_paths)
|
||||||
|
.env("TARGET", &self.config.target)
|
||||||
|
.env("PYTHON", &self.config.python)
|
||||||
|
.env("S", &src_root)
|
||||||
|
.env("RUST_BUILD_STAGE", &self.config.stage_id)
|
||||||
|
.env("RUSTC", cwd.join(&self.config.rustc_path))
|
||||||
|
.env("TMPDIR", &tmpdir)
|
||||||
|
.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 rustdoc) = self.config.rustdoc_path {
|
||||||
|
cmd.env("RUSTDOC", cwd.join(rustdoc));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref rust_demangler) = self.config.rust_demangler_path {
|
||||||
|
cmd.env("RUST_DEMANGLER", cwd.join(rust_demangler));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 != "" {
|
||||||
|
// 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("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 { stdout, stderr, status }, truncated) =
|
||||||
|
self.read2_abbreviated(cmd.spawn().expect("failed to spawn `rmake`"));
|
||||||
|
if !status.success() {
|
||||||
|
let res = ProcRes {
|
||||||
|
status,
|
||||||
|
stdout: String::from_utf8_lossy(&stdout).into_owned(),
|
||||||
|
stderr: String::from_utf8_lossy(&stderr).into_owned(),
|
||||||
|
truncated,
|
||||||
|
cmdline: format!("{:?}", cmd),
|
||||||
|
};
|
||||||
|
self.fatal_proc_rec("rmake recipe failed to complete", &res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn run_js_doc_test(&self) {
|
fn run_js_doc_test(&self) {
|
||||||
if let Some(nodejs) = &self.config.nodejs {
|
if let Some(nodejs) = &self.config.nodejs {
|
||||||
let out_dir = self.output_base_dir();
|
let out_dir = self.output_base_dir();
|
||||||
|
6
src/tools/run-make-support/Cargo.toml
Normal file
6
src/tools/run-make-support/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "run_make_support"
|
||||||
|
version = "0.0.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
151
src/tools/run-make-support/src/lib.rs
Normal file
151
src/tools/run-make-support/src/lib.rs
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
use std::env;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::process::{Command, Output};
|
||||||
|
|
||||||
|
fn setup_common_build_cmd() -> Command {
|
||||||
|
let rustc = env::var("RUSTC").unwrap();
|
||||||
|
let mut cmd = Command::new(rustc);
|
||||||
|
cmd.arg("--out-dir")
|
||||||
|
.arg(env::var("TMPDIR").unwrap())
|
||||||
|
.arg("-L")
|
||||||
|
.arg(env::var("TMPDIR").unwrap());
|
||||||
|
cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_failed_output(cmd: &str, output: Output, caller_line_number: u32) -> ! {
|
||||||
|
eprintln!("command failed at line {caller_line_number}");
|
||||||
|
eprintln!("{cmd}");
|
||||||
|
eprintln!("output status: `{}`", output.status);
|
||||||
|
eprintln!("=== STDOUT ===\n{}\n\n", String::from_utf8(output.stdout).unwrap());
|
||||||
|
eprintln!("=== STDERR ===\n{}\n\n", String::from_utf8(output.stderr).unwrap());
|
||||||
|
std::process::exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rustc() -> RustcInvocationBuilder {
|
||||||
|
RustcInvocationBuilder::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn aux_build() -> AuxBuildInvocationBuilder {
|
||||||
|
AuxBuildInvocationBuilder::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RustcInvocationBuilder {
|
||||||
|
cmd: Command,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RustcInvocationBuilder {
|
||||||
|
fn new() -> Self {
|
||||||
|
let cmd = setup_common_build_cmd();
|
||||||
|
Self { cmd }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn arg(&mut self, arg: &str) -> &mut RustcInvocationBuilder {
|
||||||
|
self.cmd.arg(arg);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
pub fn run(&mut self) -> Output {
|
||||||
|
let caller_location = std::panic::Location::caller();
|
||||||
|
let caller_line_number = caller_location.line();
|
||||||
|
|
||||||
|
let output = self.cmd.output().unwrap();
|
||||||
|
if !output.status.success() {
|
||||||
|
handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AuxBuildInvocationBuilder {
|
||||||
|
cmd: Command,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AuxBuildInvocationBuilder {
|
||||||
|
fn new() -> Self {
|
||||||
|
let mut cmd = setup_common_build_cmd();
|
||||||
|
cmd.arg("--crate-type=lib");
|
||||||
|
Self { cmd }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn arg(&mut self, arg: &str) -> &mut AuxBuildInvocationBuilder {
|
||||||
|
self.cmd.arg(arg);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
pub fn run(&mut self) -> Output {
|
||||||
|
let caller_location = std::panic::Location::caller();
|
||||||
|
let caller_line_number = caller_location.line();
|
||||||
|
|
||||||
|
let output = self.cmd.output().unwrap();
|
||||||
|
if !output.status.success() {
|
||||||
|
handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_common(bin_name: &str) -> (Command, Output) {
|
||||||
|
let target = env::var("TARGET").unwrap();
|
||||||
|
|
||||||
|
let bin_name =
|
||||||
|
if target.contains("windows") { format!("{}.exe", bin_name) } else { bin_name.to_owned() };
|
||||||
|
|
||||||
|
let mut bin_path = PathBuf::new();
|
||||||
|
bin_path.push(env::var("TMPDIR").unwrap());
|
||||||
|
bin_path.push(&bin_name);
|
||||||
|
let ld_lib_path_envvar = env::var("LD_LIB_PATH_ENVVAR").unwrap();
|
||||||
|
let mut cmd = Command::new(bin_path);
|
||||||
|
cmd.env(&ld_lib_path_envvar, {
|
||||||
|
let mut paths = vec![];
|
||||||
|
paths.push(PathBuf::from(env::var("TMPDIR").unwrap()));
|
||||||
|
for p in env::split_paths(&env::var("TARGET_RPATH_ENV").unwrap()) {
|
||||||
|
paths.push(p.to_path_buf());
|
||||||
|
}
|
||||||
|
for p in env::split_paths(&env::var(&ld_lib_path_envvar).unwrap()) {
|
||||||
|
paths.push(p.to_path_buf());
|
||||||
|
}
|
||||||
|
env::join_paths(paths.iter()).unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
if target.contains("windows") {
|
||||||
|
let mut paths = vec![];
|
||||||
|
for p in env::split_paths(&std::env::var("PATH").unwrap_or(String::new())) {
|
||||||
|
paths.push(p.to_path_buf());
|
||||||
|
}
|
||||||
|
paths.push(Path::new(&std::env::var("TARGET_RPATH_DIR").unwrap()).to_path_buf());
|
||||||
|
cmd.env("PATH", env::join_paths(paths.iter()).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = cmd.output().unwrap();
|
||||||
|
(cmd, output)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run a built binary and make sure it succeeds.
|
||||||
|
#[track_caller]
|
||||||
|
pub fn run(bin_name: &str) -> Output {
|
||||||
|
let caller_location = std::panic::Location::caller();
|
||||||
|
let caller_line_number = caller_location.line();
|
||||||
|
|
||||||
|
let (cmd, output) = run_common(bin_name);
|
||||||
|
if !output.status.success() {
|
||||||
|
handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number);
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run a built binary and make sure it fails.
|
||||||
|
#[track_caller]
|
||||||
|
pub fn run_fail(bin_name: &str) -> Output {
|
||||||
|
let caller_location = std::panic::Location::caller();
|
||||||
|
let caller_line_number = caller_location.line();
|
||||||
|
|
||||||
|
let (cmd, output) = run_common(bin_name);
|
||||||
|
if output.status.success() {
|
||||||
|
handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number);
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
@ -1,6 +0,0 @@
|
|||||||
include ../tools.mk
|
|
||||||
|
|
||||||
all:
|
|
||||||
$(RUSTC) --emit=metadata --crate-type lib stable.rs
|
|
||||||
$(RUSTC) --emit=metadata --extern stable=$(TMPDIR)/libstable.rmeta main.rs 2>&1 >/dev/null \
|
|
||||||
| $(CGREP) -e "stable since $$(cat $(S)/src/version)(-[a-zA-Z]+)?"
|
|
27
tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs
Normal file
27
tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
|
extern crate run_make_support;
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use run_make_support::{aux_build, rustc};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
aux_build()
|
||||||
|
.arg("--emit=metadata")
|
||||||
|
.arg("stable.rs")
|
||||||
|
.run();
|
||||||
|
let mut stable_path = PathBuf::from(env!("TMPDIR"));
|
||||||
|
stable_path.push("libstable.rmeta");
|
||||||
|
let output = rustc()
|
||||||
|
.arg("--emit=metadata")
|
||||||
|
.arg("--extern")
|
||||||
|
.arg(&format!("stable={}", &stable_path.to_string_lossy()))
|
||||||
|
.arg("main.rs")
|
||||||
|
.run();
|
||||||
|
|
||||||
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||||
|
let version = include_str!(concat!(env!("S"), "/src/version"));
|
||||||
|
let expected_string = format!("stable since {}", version.trim());
|
||||||
|
assert!(stderr.contains(&expected_string));
|
||||||
|
}
|
@ -1,16 +0,0 @@
|
|||||||
# ignore-cross-compile
|
|
||||||
include ../tools.mk
|
|
||||||
|
|
||||||
# Test that if we build `b` against a version of `a` that has one set
|
|
||||||
# of types, it will not run with a dylib that has a different set of
|
|
||||||
# types.
|
|
||||||
|
|
||||||
# NOTE(eddyb) this test only works with the `legacy` mangling,
|
|
||||||
# and will probably get removed once `legacy` is gone.
|
|
||||||
|
|
||||||
all:
|
|
||||||
$(RUSTC) a.rs --cfg x -C prefer-dynamic -Z unstable-options -C symbol-mangling-version=legacy
|
|
||||||
$(RUSTC) b.rs -C prefer-dynamic -Z unstable-options -C symbol-mangling-version=legacy
|
|
||||||
$(call RUN,b)
|
|
||||||
$(RUSTC) a.rs --cfg y -C prefer-dynamic -Z unstable-options -C symbol-mangling-version=legacy
|
|
||||||
$(call FAIL,b)
|
|
45
tests/run-make/a-b-a-linker-guard/rmake.rs
Normal file
45
tests/run-make/a-b-a-linker-guard/rmake.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
|
extern crate run_make_support;
|
||||||
|
|
||||||
|
use run_make_support::{run, run_fail, rustc};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
rustc()
|
||||||
|
.arg("a.rs")
|
||||||
|
.arg("--cfg")
|
||||||
|
.arg("x")
|
||||||
|
.arg("-C")
|
||||||
|
.arg("prefer-dynamic")
|
||||||
|
.arg("-Z")
|
||||||
|
.arg("unstable-options")
|
||||||
|
.arg("-C")
|
||||||
|
.arg("symbol-mangling-version=legacy")
|
||||||
|
.run();
|
||||||
|
|
||||||
|
rustc()
|
||||||
|
.arg("b.rs")
|
||||||
|
.arg("-C")
|
||||||
|
.arg("prefer-dynamic")
|
||||||
|
.arg("-Z")
|
||||||
|
.arg("unstable-options")
|
||||||
|
.arg("-C")
|
||||||
|
.arg("symbol-mangling-version=legacy")
|
||||||
|
.run();
|
||||||
|
|
||||||
|
run("b");
|
||||||
|
|
||||||
|
rustc()
|
||||||
|
.arg("a.rs")
|
||||||
|
.arg("--cfg")
|
||||||
|
.arg("y")
|
||||||
|
.arg("-C")
|
||||||
|
.arg("prefer-dynamic")
|
||||||
|
.arg("-Z")
|
||||||
|
.arg("unstable-options")
|
||||||
|
.arg("-C")
|
||||||
|
.arg("symbol-mangling-version=legacy")
|
||||||
|
.run();
|
||||||
|
|
||||||
|
run_fail("b");
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user