@@ -3433,29 +3433,51 @@ impl<'test> TestCx<'test> {
34333433
34343434 fn run_rmake_v2_test ( & self ) {
34353435 // For `run-make` V2, we need to perform 2 steps to build and run a `run-make` V2 recipe
3436- // (`rmake.rs`) to run the actual tests. The support library is already built as a tool
3437- // dylib and is available under `build/$TARGET/stageN-tools-bin/librun_make_support.rlib`.
3436+ // (`rmake.rs`) to run the actual tests. The support library is already built as a tool rust
3437+ // library and is available under `build/$TARGET/stageN-tools-bin/librun_make_support.rlib`.
34383438 //
3439- // 1. We need to build the recipe `rmake.rs` and link in the support library.
3440- // 2. We need to run the recipe to build and run the tests.
3441- let cwd = env:: current_dir ( ) . unwrap ( ) ;
3442- let src_root = self . config . src_base . parent ( ) . unwrap ( ) . parent ( ) . unwrap ( ) ;
3443- let src_root = cwd. join ( & src_root) ;
3444- let build_root = self . config . build_base . parent ( ) . unwrap ( ) . parent ( ) . unwrap ( ) ;
3445- let build_root = cwd. join ( & build_root) ;
3439+ // 1. We need to build the recipe `rmake.rs` as a binary and link in the `run_make_support`
3440+ // library.
3441+ // 2. We need to run the recipe binary.
3442+
3443+ // So we assume the rust-lang/rust project setup looks like the following (our `.` is the
3444+ // top-level directory, irrelevant entries to our purposes omitted):
3445+ //
3446+ // ```
3447+ // . // <- `source_root`
3448+ // ├── build/ // <- `build_root`
3449+ // ├── compiler/
3450+ // ├── library/
3451+ // ├── src/
3452+ // │ └── tools/
3453+ // │ └── run_make_support/
3454+ // └── tests
3455+ // └── run-make/
3456+ // ```
3457+
3458+ // `source_root` is the top-level directory containing the rust-lang/rust checkout.
3459+ let source_root =
3460+ self . config . find_rust_src_root ( ) . expect ( "could not determine rust source root" ) ;
3461+ // `self.config.build_base` is actually the build base folder + "test" + test suite name, it
3462+ // looks like `build/<host_triple>/test/run-make`. But we want `build/<host_triple>/`. Note
3463+ // that the `build` directory does not need to be called `build`, nor does it need to be
3464+ // under `source_root`, so we must compute it based off of `self.config.build_base`.
3465+ let build_root =
3466+ self . config . build_base . parent ( ) . and_then ( Path :: parent) . unwrap ( ) . to_path_buf ( ) ;
34463467
34473468 // We construct the following directory tree for each rmake.rs test:
34483469 // ```
3449- // base_dir/
3470+ // < base_dir> /
34503471 // rmake.exe
34513472 // rmake_out/
34523473 // ```
3453- // having the executable separate from the output artifacts directory allows the recipes to
3454- // `remove_dir_all($TMPDIR)` without running into permission denied issues because
3455- // the executable is not under the `rmake_out/` directory.
3474+ // having the recipe executable separate from the output artifacts directory allows the
3475+ // recipes to `remove_dir_all($TMPDIR)` without running into issues related trying to remove
3476+ // a currently running executable because the recipe executable is not under the
3477+ // `rmake_out/` directory.
34563478 //
34573479 // This setup intentionally diverges from legacy Makefile run-make tests.
3458- let base_dir = cwd . join ( self . output_base_name ( ) ) ;
3480+ let base_dir = self . output_base_name ( ) ;
34593481 if base_dir. exists ( ) {
34603482 self . aggressive_rm_rf ( & base_dir) . unwrap ( ) ;
34613483 }
@@ -3477,120 +3499,186 @@ impl<'test> TestCx<'test> {
34773499 }
34783500 }
34793501
3480- // HACK: assume stageN-target, we only want stageN.
3502+ // `self.config.stage_id` looks like `stage1-<target_triple>`, but we only want
3503+ // the `stage1` part as that is what the output directories of bootstrap are prefixed with.
3504+ // Note that this *assumes* build layout from bootstrap is produced as:
3505+ //
3506+ // ```
3507+ // build/<target_triple>/ // <- this is `build_root`
3508+ // ├── stage0
3509+ // ├── stage0-bootstrap-tools
3510+ // ├── stage0-codegen
3511+ // ├── stage0-rustc
3512+ // ├── stage0-std
3513+ // ├── stage0-sysroot
3514+ // ├── stage0-tools
3515+ // ├── stage0-tools-bin
3516+ // ├── stage1
3517+ // ├── stage1-std
3518+ // ├── stage1-tools
3519+ // ├── stage1-tools-bin
3520+ // └── test
3521+ // ```
3522+ // FIXME(jieyouxu): improve the communication between bootstrap and compiletest here so
3523+ // we don't have to hack out a `stageN`.
34813524 let stage = self . config . stage_id . split ( '-' ) . next ( ) . unwrap ( ) ;
34823525
3483- // First, we construct the path to the built support library.
3484- let mut support_lib_path = PathBuf :: new ( ) ;
3485- support_lib_path. push ( & build_root) ;
3486- support_lib_path. push ( format ! ( "{}-tools-bin" , stage) ) ;
3487- support_lib_path. push ( "librun_make_support.rlib" ) ;
3526+ // In order to link in the support library as a rlib when compiling recipes, we need three
3527+ // paths:
3528+ // 1. Path of the built support library rlib itself.
3529+ // 2. Path of the built support library's dependencies directory.
3530+ // 3. Path of the built support library's dependencies' dependencies directory.
3531+ //
3532+ // The paths look like
3533+ //
3534+ // ```
3535+ // build/<target_triple>/
3536+ // ├── stageN-tools-bin/
3537+ // │ └── librun_make_support.rlib // <- support rlib itself
3538+ // ├── stageN-tools/
3539+ // │ ├── release/deps/ // <- deps of deps
3540+ // │ └── <host_triple>/release/deps/ // <- deps
3541+ // ```
3542+ //
3543+ // FIXME(jieyouxu): there almost certainly is a better way to do this (specifically how the
3544+ // support lib and its deps are organized, can't we copy them to the tools-bin dir as
3545+ // well?), but this seems to work for now.
34883546
3489- let mut stage_std_path = PathBuf :: new ( ) ;
3490- stage_std_path. push ( & build_root) ;
3491- stage_std_path. push ( & stage) ;
3492- stage_std_path. push ( "lib" ) ;
3547+ let stage_tools_bin = build_root. join ( format ! ( "{stage}-tools-bin" ) ) ;
3548+ let support_lib_path = stage_tools_bin. join ( "librun_make_support.rlib" ) ;
34933549
3494- // Then, we need to build the recipe `rmake.rs` and link in the support library.
3495- let recipe_bin = base_dir. join ( if self . config . target . contains ( "windows" ) {
3496- "rmake.exe"
3497- } else {
3498- "rmake"
3499- } ) ;
3500-
3501- let mut support_lib_deps = PathBuf :: new ( ) ;
3502- support_lib_deps. push ( & build_root) ;
3503- support_lib_deps. push ( format ! ( "{}-tools" , stage) ) ;
3504- support_lib_deps. push ( & self . config . host ) ;
3505- support_lib_deps. push ( "release" ) ;
3506- support_lib_deps. push ( "deps" ) ;
3507-
3508- let mut support_lib_deps_deps = PathBuf :: new ( ) ;
3509- support_lib_deps_deps. push ( & build_root) ;
3510- support_lib_deps_deps. push ( format ! ( "{}-tools" , stage) ) ;
3511- support_lib_deps_deps. push ( "release" ) ;
3512- support_lib_deps_deps. push ( "deps" ) ;
3513-
3514- debug ! ( ?support_lib_deps) ;
3515- debug ! ( ?support_lib_deps_deps) ;
3516-
3517- let orig_dylib_env_paths =
3550+ let stage_tools = build_root. join ( format ! ( "{stage}-tools" ) ) ;
3551+ let support_lib_deps = stage_tools. join ( & self . config . host ) . join ( "release" ) . join ( "deps" ) ;
3552+ let support_lib_deps_deps = stage_tools. join ( "release" ) . join ( "deps" ) ;
3553+
3554+ // To compile the recipe with rustc, we need to provide suitable dynamic library search
3555+ // paths to rustc. This includes both:
3556+ // 1. The "base" dylib search paths that was provided to compiletest, e.g. `LD_LIBRARY_PATH`
3557+ // on some linux distros.
3558+ // 2. Specific library paths in `self.config.compile_lib_path` needed for running rustc.
3559+
3560+ let base_dylib_search_paths =
35183561 Vec :: from_iter ( env:: split_paths ( & env:: var ( dylib_env_var ( ) ) . unwrap ( ) ) ) ;
35193562
3520- let mut host_dylib_env_paths = Vec :: new ( ) ;
3521- host_dylib_env_paths. push ( cwd. join ( & self . config . compile_lib_path ) ) ;
3522- host_dylib_env_paths. extend ( orig_dylib_env_paths. iter ( ) . cloned ( ) ) ;
3523- let host_dylib_env_paths = env:: join_paths ( host_dylib_env_paths) . unwrap ( ) ;
3563+ let host_dylib_search_paths = {
3564+ let mut paths = vec ! [ self . config. compile_lib_path. clone( ) ] ;
3565+ paths. extend ( base_dylib_search_paths. iter ( ) . cloned ( ) ) ;
3566+ paths
3567+ } ;
3568+
3569+ // Calculate the paths of the recipe binary. As previously discussed, this is placed at
3570+ // `<base_dir>/<bin_name>` with `bin_name` being `rmake` or `rmake.exe` depending on
3571+ // platform.
3572+ let recipe_bin = {
3573+ let mut p = base_dir. join ( "rmake" ) ;
3574+ p. set_extension ( env:: consts:: EXE_EXTENSION ) ;
3575+ p
3576+ } ;
35243577
3525- let mut cmd = Command :: new ( & self . config . rustc_path ) ;
3526- cmd. arg ( "-o" )
3578+ let mut rustc = Command :: new ( & self . config . rustc_path ) ;
3579+ rustc
3580+ . arg ( "-o" )
35273581 . arg ( & recipe_bin)
3582+ // Specify library search paths for `run_make_support`.
35283583 . arg ( format ! ( "-Ldependency={}" , & support_lib_path. parent( ) . unwrap( ) . to_string_lossy( ) ) )
35293584 . arg ( format ! ( "-Ldependency={}" , & support_lib_deps. to_string_lossy( ) ) )
35303585 . arg ( format ! ( "-Ldependency={}" , & support_lib_deps_deps. to_string_lossy( ) ) )
3586+ // Provide `run_make_support` as extern prelude, so test writers don't need to write
3587+ // `extern run_make_support;`.
35313588 . arg ( "--extern" )
35323589 . arg ( format ! ( "run_make_support={}" , & support_lib_path. to_string_lossy( ) ) )
35333590 . arg ( "--edition=2021" )
35343591 . arg ( & self . testpaths . file . join ( "rmake.rs" ) )
3535- . env ( "TARGET" , & self . config . target )
3536- . env ( "PYTHON" , & self . config . python )
3537- . env ( "RUST_BUILD_STAGE" , & self . config . stage_id )
3538- . env ( "RUSTC" , cwd. join ( & self . config . rustc_path ) )
3539- . env ( "LD_LIB_PATH_ENVVAR" , dylib_env_var ( ) )
3540- . env ( dylib_env_var ( ) , & host_dylib_env_paths)
3541- . env ( "HOST_RPATH_DIR" , cwd. join ( & self . config . compile_lib_path ) )
3542- . env ( "TARGET_RPATH_DIR" , cwd. join ( & self . config . run_lib_path ) )
3543- . env ( "LLVM_COMPONENTS" , & self . config . llvm_components ) ;
3592+ // Provide necessary library search paths for rustc.
3593+ . env ( dylib_env_var ( ) , & env:: join_paths ( host_dylib_search_paths) . unwrap ( ) ) ;
35443594
35453595 // In test code we want to be very pedantic about values being silently discarded that are
35463596 // annotated with `#[must_use]`.
3547- cmd. arg ( "-Dunused_must_use" ) ;
3548-
3597+ rustc. arg ( "-Dunused_must_use" ) ;
3598+
3599+ // > `cg_clif` uses `COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0` for running the rustc
3600+ // > test suite. With the introduction of rmake.rs this broke. `librun_make_support.rlib` is
3601+ // > compiled using the bootstrap rustc wrapper which sets `--sysroot
3602+ // > build/aarch64-unknown-linux-gnu/stage0-sysroot`, but then compiletest will compile
3603+ // > `rmake.rs` using the sysroot of the bootstrap compiler causing it to not find the
3604+ // > `libstd.rlib` against which `librun_make_support.rlib` is compiled.
3605+ //
3606+ // The gist here is that we have to pass the proper stage0 sysroot if we want
3607+ //
3608+ // ```
3609+ // $ COMPILETEST_FORCE_STAGE0=1 ./x test run-make --stage 0
3610+ // ```
3611+ //
3612+ // to work correctly.
3613+ //
3614+ // See <https://github.com/rust-lang/rust/pull/122248> for more background.
35493615 if std:: env:: var_os ( "COMPILETEST_FORCE_STAGE0" ) . is_some ( ) {
3550- let mut stage0_sysroot = build_root. clone ( ) ;
3551- stage0_sysroot. push ( "stage0-sysroot" ) ;
3552- debug ! ( ?stage0_sysroot) ;
3553- debug ! ( exists = stage0_sysroot. exists( ) ) ;
3554-
3555- cmd. arg ( "--sysroot" ) . arg ( & stage0_sysroot) ;
3616+ let stage0_sysroot = build_root. join ( "stage0-sysroot" ) ;
3617+ rustc. arg ( "--sysroot" ) . arg ( & stage0_sysroot) ;
35563618 }
35573619
3558- let res = self . run_command_to_procres ( & mut cmd) ;
3620+ // Now run rustc to build the recipe.
3621+ let res = self . run_command_to_procres ( & mut rustc) ;
35593622 if !res. status . success ( ) {
35603623 self . fatal_proc_rec ( "run-make test failed: could not build `rmake.rs` recipe" , & res) ;
35613624 }
35623625
3563- // Finally, we need to run the recipe binary to build and run the actual tests.
3564- debug ! ( ?recipe_bin) ;
3626+ // To actually run the recipe, we have to provide the recipe with a bunch of information
3627+ // provided through env vars.
3628+
3629+ // Compute stage-specific standard library paths.
3630+ let stage_std_path = build_root. join ( & stage) . join ( "lib" ) ;
35653631
3566- let mut dylib_env_paths = orig_dylib_env_paths. clone ( ) ;
3567- dylib_env_paths. push ( support_lib_path. parent ( ) . unwrap ( ) . to_path_buf ( ) ) ;
3568- dylib_env_paths. push ( stage_std_path. join ( "rustlib" ) . join ( & self . config . host ) . join ( "lib" ) ) ;
3569- let dylib_env_paths = env:: join_paths ( dylib_env_paths) . unwrap ( ) ;
3632+ // Compute dynamic library search paths for recipes.
3633+ let recipe_dylib_search_paths = {
3634+ let mut paths = base_dylib_search_paths. clone ( ) ;
3635+ paths. push ( support_lib_path. parent ( ) . unwrap ( ) . to_path_buf ( ) ) ;
3636+ paths. push ( stage_std_path. join ( "rustlib" ) . join ( & self . config . host ) . join ( "lib" ) ) ;
3637+ paths
3638+ } ;
35703639
3571- let mut target_rpath_env_path = Vec :: new ( ) ;
3572- target_rpath_env_path. push ( & rmake_out_dir) ;
3573- target_rpath_env_path. extend ( & orig_dylib_env_paths) ;
3574- let target_rpath_env_path = env:: join_paths ( target_rpath_env_path) . unwrap ( ) ;
3640+ // Compute runtime library search paths for recipes. This is target-specific.
3641+ let target_runtime_dylib_search_paths = {
3642+ let mut paths = vec ! [ rmake_out_dir. clone( ) ] ;
3643+ paths. extend ( base_dylib_search_paths. iter ( ) . cloned ( ) ) ;
3644+ paths
3645+ } ;
35753646
3647+ // FIXME(jieyouxu): please rename `TARGET_RPATH_ENV`, `HOST_RPATH_DIR` and
3648+ // `TARGET_RPATH_DIR`, it is **extremely** confusing!
35763649 let mut cmd = Command :: new ( & recipe_bin) ;
35773650 cmd. current_dir ( & rmake_out_dir)
35783651 . stdout ( Stdio :: piped ( ) )
35793652 . stderr ( Stdio :: piped ( ) )
3653+ // Provide the target-specific env var that is used to record dylib search paths. For
3654+ // example, this could be `LD_LIBRARY_PATH` on some linux distros but `PATH` on Windows.
35803655 . env ( "LD_LIB_PATH_ENVVAR" , dylib_env_var ( ) )
3581- . env ( "TARGET_RPATH_ENV" , & target_rpath_env_path)
3582- . env ( dylib_env_var ( ) , & dylib_env_paths)
3656+ // Provide the dylib search paths.
3657+ . env ( dylib_env_var ( ) , & env:: join_paths ( recipe_dylib_search_paths) . unwrap ( ) )
3658+ // Provide runtime dylib search paths.
3659+ . env ( "TARGET_RPATH_ENV" , & env:: join_paths ( target_runtime_dylib_search_paths) . unwrap ( ) )
3660+ // Provide the target.
35833661 . env ( "TARGET" , & self . config . target )
3662+ // Some tests unfortunately still need Python, so provide path to a Python interpreter.
35843663 . env ( "PYTHON" , & self . config . python )
3585- . env ( "SOURCE_ROOT" , & src_root)
3586- . env ( "RUST_BUILD_STAGE" , & self . config . stage_id )
3587- . env ( "RUSTC" , cwd. join ( & self . config . rustc_path ) )
3588- . env ( "HOST_RPATH_DIR" , cwd. join ( & self . config . compile_lib_path ) )
3589- . env ( "TARGET_RPATH_DIR" , cwd. join ( & self . config . run_lib_path ) )
3664+ // Provide path to checkout root. This is the top-level directory containing
3665+ // rust-lang/rust checkout.
3666+ . env ( "SOURCE_ROOT" , & source_root)
3667+ // Provide path to stage-corresponding rustc.
3668+ . env ( "RUSTC" , & self . config . rustc_path )
3669+ // Provide the directory to libraries that are needed to run the *compiler*. This is not
3670+ // to be confused with `TARGET_RPATH_ENV` or `TARGET_RPATH_DIR`. This is needed if the
3671+ // recipe wants to invoke rustc.
3672+ . env ( "HOST_RPATH_DIR" , & self . config . compile_lib_path )
3673+ // Provide the directory to libraries that might be needed to run compiled binaries
3674+ // (further compiled by the recipe!).
3675+ . env ( "TARGET_RPATH_DIR" , & self . config . run_lib_path )
3676+ // Provide which LLVM components are available (e.g. which LLVM components are provided
3677+ // through a specific CI runner).
35903678 . env ( "LLVM_COMPONENTS" , & self . config . llvm_components ) ;
35913679
35923680 if let Some ( ref rustdoc) = self . config . rustdoc_path {
3593- cmd. env ( "RUSTDOC" , cwd . join ( rustdoc) ) ;
3681+ cmd. env ( "RUSTDOC" , source_root . join ( rustdoc) ) ;
35943682 }
35953683
35963684 if let Some ( ref node) = self . config . nodejs {
0 commit comments