Skip to content

Build script fingerprints do not track dependencies to links build scripts. #6780

@ehuss

Description

@ehuss

The fingerprint for running a build script does not include information about links dependency build scripts. This means that if the dependent build script runs, but the top-level one does not (such as if it was cancelled, or built separately), it will not re-run the top-level build script.

Fixing this may be quite difficult. Due to the way build script Fingerprint::locals are recomputed within the closure, the information for the links dependencies is not readily available. These Fingerprints could be shared with Arc in Context::fingerprints, but that would require making locals a Mutex (or changing the entire Fingerprint to be Arc<Mutex<Fingerprint>>). This is also complicated by the fact that build script fingerprints need access to Context::build_explicit_deps which is not pre-populated before fingerprints are computed.

Below is a demonstration of the problem.

#[test]
fn links_interrupted_can_restart() {
    // Test for a `links` dependent build script getting canceled and then
    // restarted. Steps:
    // 1. Build to establish fingerprints.
    // 2. Change something (an env var in this case) that triggers the
    //    dependent build script to run again. Kill the top-level build script
    //    while it is running (such as hitting Ctrl-C).
    // 3. Run the build again, it should re-run the build script.
    let bar = project()
        .at("bar")
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "bar"
            version = "0.5.0"
            authors = []
            links = "foo"
            build = "build.rs"
            "#,
        )
        .file("src/lib.rs", "")
        .file(
            "build.rs",
            r#"
            fn main() {
                println!("cargo:rerun-if-env-changed=SOMEVAR");
            }
            "#,
        )
        .build();

    let p = project()
        .file(
            "Cargo.toml",
            &format!(
                r#"
                [package]
                name = "foo"
                version = "0.5.0"
                authors = []
                build = "build.rs"

                [dependencies.bar]
                path = '{}'
                "#,
                bar.root().display()
            ),
        )
        .file("src/lib.rs", "")
        .file(
            "build.rs",
            r#"
            use std::env;
            fn main() {
                println!("cargo:rebuild-if-changed=build.rs");
                if std::path::Path::new("abort").exists() {
                    panic!("Crash!");
                }
            }
            "#,
        )
        .build();

    p.cargo("build").run();
    // Simulate the user hitting Ctrl-C during a build.
    p.change_file("abort", "");
    // Set SOMEVAR to trigger a rebuild.
    p.cargo("build")
        .env("SOMEVAR", "1")
        .with_stderr_contains("[..]Crash![..]")
        .with_status(101)
        .run();
    fs::remove_file(p.root().join("abort")).unwrap();
    // Try again without aborting the script.
    // ***This is currently broken, the script does not re-run.
    p.cargo("build -v")
        .env("SOMEVAR", "1")
        .with_stderr_contains("[RUNNING] [..]/foo-[..]/build-script-build[..]")
        .run();
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions