|  | 
| 1 |  | -use run_make_support::python_command; | 
|  | 1 | +// Check that crates in the sysroot are treated as unstable, unless they are | 
|  | 2 | +// on a list of known-stable sysroot crates. | 
|  | 3 | + | 
|  | 4 | +use std::path::{Path, PathBuf}; | 
|  | 5 | +use std::str; | 
|  | 6 | + | 
|  | 7 | +use run_make_support::{rfs, rustc, target}; | 
|  | 8 | + | 
|  | 9 | +fn is_stable_crate(name: &str) -> bool { | 
|  | 10 | +    matches!(name, "std" | "alloc" | "core" | "proc_macro") | 
|  | 11 | +} | 
| 2 | 12 | 
 | 
| 3 | 13 | fn main() { | 
| 4 |  | -    python_command().arg("test.py").run(); | 
|  | 14 | +    for cr in get_unstable_sysroot_crates() { | 
|  | 15 | +        check_crate_is_unstable(&cr); | 
|  | 16 | +    } | 
|  | 17 | +    println!("Done"); | 
|  | 18 | +} | 
|  | 19 | + | 
|  | 20 | +#[derive(Debug)] | 
|  | 21 | +struct Crate { | 
|  | 22 | +    name: String, | 
|  | 23 | +    path: PathBuf, | 
|  | 24 | +} | 
|  | 25 | + | 
|  | 26 | +fn check_crate_is_unstable(cr: &Crate) { | 
|  | 27 | +    let Crate { name, path } = cr; | 
|  | 28 | + | 
|  | 29 | +    print!("- Verifying that sysroot crate '{name}' is an unstable crate ..."); | 
|  | 30 | + | 
|  | 31 | +    // Trying to use this crate from a user program should fail. | 
|  | 32 | +    let output = rustc() | 
|  | 33 | +        .crate_type("rlib") | 
|  | 34 | +        .target(target()) | 
|  | 35 | +        .extern_(name, path) | 
|  | 36 | +        .input("-") | 
|  | 37 | +        .stdin(format!("extern crate {name};")) | 
|  | 38 | +        .run_fail(); | 
|  | 39 | + | 
|  | 40 | +    // Make sure it failed for the intended reason, not some other reason. | 
|  | 41 | +    // (The actual feature required varies between crates.) | 
|  | 42 | +    output.assert_stderr_contains("use of unstable library feature"); | 
|  | 43 | + | 
|  | 44 | +    println!(" OK"); | 
|  | 45 | +} | 
|  | 46 | + | 
|  | 47 | +fn get_unstable_sysroot_crates() -> Vec<Crate> { | 
|  | 48 | +    let sysroot = PathBuf::from(rustc().print("sysroot").run().stdout_utf8().trim()); | 
|  | 49 | +    let sysroot_libs_dir = sysroot.join("lib").join("rustlib").join(target()).join("lib"); | 
|  | 50 | +    println!("Sysroot libs dir: {sysroot_libs_dir:?}"); | 
|  | 51 | + | 
|  | 52 | +    // Generate a list of all library crates in the sysroot. | 
|  | 53 | +    let sysroot_crates = get_all_crates_in_dir(&sysroot_libs_dir); | 
|  | 54 | +    println!( | 
|  | 55 | +        "Found {} sysroot crates: {:?}", | 
|  | 56 | +        sysroot_crates.len(), | 
|  | 57 | +        sysroot_crates.iter().map(|cr| &cr.name).collect::<Vec<_>>() | 
|  | 58 | +    ); | 
|  | 59 | + | 
|  | 60 | +    // Self-check: If we didn't find `core`, we probably checked the wrong directory. | 
|  | 61 | +    assert!( | 
|  | 62 | +        sysroot_crates.iter().any(|cr| cr.name == "core"), | 
|  | 63 | +        "Couldn't find `core` in {sysroot_libs_dir:?}" | 
|  | 64 | +    ); | 
|  | 65 | + | 
|  | 66 | +    let unstable_sysroot_crates = | 
|  | 67 | +        sysroot_crates.into_iter().filter(|cr| !is_stable_crate(&cr.name)).collect::<Vec<_>>(); | 
|  | 68 | +    // Self-check: There should be at least one unstable crate in the directory. | 
|  | 69 | +    assert!( | 
|  | 70 | +        !unstable_sysroot_crates.is_empty(), | 
|  | 71 | +        "Couldn't find any unstable crates in {sysroot_libs_dir:?}" | 
|  | 72 | +    ); | 
|  | 73 | +    unstable_sysroot_crates | 
|  | 74 | +} | 
|  | 75 | + | 
|  | 76 | +fn get_all_crates_in_dir(libs_dir: &Path) -> Vec<Crate> { | 
|  | 77 | +    let mut libs = vec![]; | 
|  | 78 | +    rfs::read_dir_entries(libs_dir, |path| { | 
|  | 79 | +        if !path.is_file() { | 
|  | 80 | +            return; | 
|  | 81 | +        } | 
|  | 82 | +        if let Some(name) = crate_name_from_path(path) { | 
|  | 83 | +            libs.push(Crate { name, path: path.to_owned() }); | 
|  | 84 | +        } | 
|  | 85 | +    }); | 
|  | 86 | +    libs.sort_by(|a, b| a.name.cmp(&b.name)); | 
|  | 87 | +    libs | 
|  | 88 | +} | 
|  | 89 | + | 
|  | 90 | +/// Treat a file as a crate if its name begins with `lib` and ends with `.rlib`. | 
|  | 91 | +/// The crate name is the part before the first hyphen (if any). | 
|  | 92 | +fn crate_name_from_path(path: &Path) -> Option<String> { | 
|  | 93 | +    let name = path | 
|  | 94 | +        .file_name()? | 
|  | 95 | +        .to_str()? | 
|  | 96 | +        .strip_prefix("lib")? | 
|  | 97 | +        .strip_suffix(".rlib")? | 
|  | 98 | +        .split('-') | 
|  | 99 | +        .next() | 
|  | 100 | +        .expect("split always yields at least one string"); | 
|  | 101 | +    Some(name.to_owned()) | 
| 5 | 102 | } | 
0 commit comments