mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 10:13:54 +00:00
Auto merge of #113026 - jieyouxu:run-make-v2, r=bjorn3
Introduce `run-make` V2 infrastructure, a `run_make_support` library and port over 2 tests as example ## Preface See [issue #40713: Switch run-make tests from Makefiles to rust](https://github.com/rust-lang/rust/issues/40713) for more context. ## Basic Description of `run-make` V2 `run-make` V2 aims to eliminate the dependency on `make` and `Makefile`s for building `run-make`-style tests. Makefiles are replaced by *recipes* (`rmake.rs`). The current implementation runs `run-make` V2 tests in 3 steps: 1. We build the support library `run_make_support` which the `rmake.rs` recipes depend on as a tool lib. 2. We build the recipe `rmake.rs` and link in the support library. 3. We run the recipe to build and run the tests. `rmake.rs` is basically a replacement for `Makefile`, and allows running arbitrary Rust code. The support library is built using cargo, and so can depend on external crates if desired. The infrastructure implemented by this PR is very barebones, and is the minimally required infrastructure needed to build, run and pass the two example `run-make` tests ported over to the new infrastructure. ### Example `run-make` V2 test ```rs // 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)); } ``` ## Follow Up Work - [ ] Adjust rustc-dev-guide docs
This commit is contained in:
commit
17edacef07
@ -3274,6 +3274,10 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "run_make_support"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "rust-demangler"
|
||||
version = "0.0.1"
|
||||
|
@ -10,6 +10,7 @@ members = [
|
||||
"src/tools/clippy",
|
||||
"src/tools/clippy/clippy_dev",
|
||||
"src/tools/compiletest",
|
||||
"src/tools/run-make-support",
|
||||
"src/tools/error_index_generator",
|
||||
"src/tools/linkchecker",
|
||||
"src/tools/lint-docs",
|
||||
|
@ -1327,6 +1327,52 @@ macro_rules! coverage_test_alias {
|
||||
};
|
||||
}
|
||||
|
||||
#[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!(RunPassValgrind {
|
||||
@ -1361,7 +1407,40 @@ host_test!(RustdocJson { path: "tests/rustdoc-json", mode: "rustdoc-json", suite
|
||||
|
||||
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 {
|
||||
path: "tests/run-make-fulldeps",
|
||||
|
@ -655,13 +655,21 @@ fn collect_tests_from_dir(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if config.mode == Mode::RunMake && dir.join("Makefile").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 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() {
|
||||
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
|
||||
@ -733,8 +741,17 @@ fn make_test(
|
||||
poisoned: &mut bool,
|
||||
) -> Vec<test::TestDescAndFn> {
|
||||
let test_path = if config.mode == Mode::RunMake {
|
||||
// Parse directives in the Makefile
|
||||
testpaths.file.join("Makefile")
|
||||
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")
|
||||
}
|
||||
} else {
|
||||
PathBuf::from(&testpaths.file)
|
||||
};
|
||||
|
@ -3570,6 +3570,17 @@ impl<'test> TestCx<'test> {
|
||||
}
|
||||
|
||||
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 src_root = self.config.src_base.parent().unwrap().parent().unwrap();
|
||||
let src_root = cwd.join(&src_root);
|
||||
@ -3737,6 +3748,238 @@ impl<'test> TestCx<'test> {
|
||||
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) {
|
||||
if let Some(nodejs) = &self.config.nodejs {
|
||||
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