diff --git a/Cargo.lock b/Cargo.lock index e37e8614af2..6827946124c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3274,6 +3274,10 @@ dependencies = [ "serde_json", ] +[[package]] +name = "run_make_support" +version = "0.0.0" + [[package]] name = "rust-demangler" version = "0.0.1" diff --git a/Cargo.toml b/Cargo.toml index 2ea16c22666..5847a817e76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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", diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index a2c6e79d5e2..4a4497e57db 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -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!(RunPassValgrind { @@ -1361,7 +1407,40 @@ fn run(self, builder: &Builder<'_>) { 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", diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 57a82eb37ed..b32a5a4bf1a 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -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 { 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) }; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index f1ba9ab4767..a942aa9dc90 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3570,6 +3570,17 @@ fn run_incremental_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 src_root = self.config.src_base.parent().unwrap().parent().unwrap(); let src_root = cwd.join(&src_root); @@ -3737,6 +3748,238 @@ fn aggressive_rm_rf(&self, path: &Path) -> io::Result<()> { 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::>() + .join(" "); + let cxxflags = self + .config + .cxxflags + .split(' ') + .map(|s| s.replace("/", "-")) + .collect::>() + .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(); diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml new file mode 100644 index 00000000000..178deae6499 --- /dev/null +++ b/src/tools/run-make-support/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "run_make_support" +version = "0.0.0" +edition = "2021" + +[dependencies] diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs new file mode 100644 index 00000000000..820218732ce --- /dev/null +++ b/src/tools/run-make-support/src/lib.rs @@ -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 +} diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/Makefile b/tests/run-make/CURRENT_RUSTC_VERSION/Makefile deleted file mode 100644 index 7940dae207b..00000000000 --- a/tests/run-make/CURRENT_RUSTC_VERSION/Makefile +++ /dev/null @@ -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]+)?" diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs new file mode 100644 index 00000000000..586f4e4095f --- /dev/null +++ b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs @@ -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)); +} diff --git a/tests/run-make/a-b-a-linker-guard/Makefile b/tests/run-make/a-b-a-linker-guard/Makefile deleted file mode 100644 index 43282eae09c..00000000000 --- a/tests/run-make/a-b-a-linker-guard/Makefile +++ /dev/null @@ -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) diff --git a/tests/run-make/a-b-a-linker-guard/rmake.rs b/tests/run-make/a-b-a-linker-guard/rmake.rs new file mode 100644 index 00000000000..ef4813e1214 --- /dev/null +++ b/tests/run-make/a-b-a-linker-guard/rmake.rs @@ -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"); +}