Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LTO can cause dependencies to rebuild between build and test #8762

Open
ehuss opened this issue Oct 8, 2020 · 1 comment
Open

LTO can cause dependencies to rebuild between build and test #8762

ehuss opened this issue Oct 8, 2020 · 1 comment
Labels
A-lto Area: link-time optimization A-rebuild-detection Area: rebuild detection and fingerprinting S-triage Status: This issue is waiting on initial triage.

Comments

@ehuss
Copy link
Contributor

ehuss commented Oct 8, 2020

If you have lto enabled in the profile, then cargo build followed by cargo test can result in all dependencies being rebuilt. This is probably not what people want or expect.

#[cargo_test]
fn build_test_rebuild() {
    Package::new("bar", "1.0.0").publish();
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                version = "0.1.0"

                [dependencies]
                bar = "1.0"

                [profile.release]
                lto = true
            "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build --release -v")
        .with_stderr(
            "\
[UPDATING] [..]
[DOWNLOADING] crates ...
[DOWNLOADED] bar v1.0.0 [..]
[COMPILING] bar v1.0.0
[RUNNING] `rustc --crate-name bar [..]-C linker-plugin-lto[..]
[COMPILING] foo v0.1.0 [..]
[RUNNING] `rustc --crate-name foo [..]-C linker-plugin-lto[..]
[FINISHED] [..]
",
        )
        .run();
    // FIXME: this rebuilds `bar`, but that is probably undesired.
    p.cargo("test --release -v")
        .with_stderr(
            "\
[COMPILING] bar v1.0.0
[RUNNING] `rustc --crate-name bar [..]-C embed-bitcode=no[..]
[COMPILING] foo v0.1.0 [..]
[RUNNING] `rustc --crate-name foo src/lib.rs [..]-C embed-bitcode=no [..]
[RUNNING] `rustc --crate-name foo src/lib.rs [..]-C embed-bitcode=no [..]--test[..]
[FINISHED] [..]
[RUNNING] [..]
[DOCTEST] foo
[RUNNING] `rustdoc --crate-type lib --test [..]-C embed-bitcode=no[..]
",
        )
        .run();
}

The exact scenario depends on the structure of the project and the flags used, but for the above example:

  • build builds dependencies with bitcode, because that's all LTO needs.
  • test builds only with object code, because tests need that to link, but there isn't anything that actually needs LTO.

A similar scenario, if you have a main.rs in the project, it is slightly different:

  • build builds dependencies with bitcode, because that's all LTO needs.
  • test builds dependencies with both bitcode and object code, because the tests need object code, and the binary needs bitcode for LTO.

The user can fix this by adding lto to the test or bench profile (depending on whether you use the --release flag). Alternatively, one can just not assume that test --release will share artifacts. I guess another option would be to give the user the ability to disable the bitcode-only optimization.

This particular scenario will be fixed by named-profiles, because the test/bench profiles implicitly inherit the dev/release profile settings. Of course, that means tests will then be LTO'd, which can be quite expensive.

I think it should be fine to wait for named-profiles to be stabilized to resolve this issue. However, I wanted to file it to track the concern. I also think it might warrant having a higher priority for moving named-profiles forward.

A real-world example of this is rustup's CI setup.

@ehuss ehuss added A-rebuild-detection Area: rebuild detection and fingerprinting A-lto Area: link-time optimization labels Oct 8, 2020
@krtab
Copy link
Contributor

krtab commented Nov 12, 2020

Hi,

I have been hit by this. Here is the issue I started writting:

If I have LTO on in release mode and run:

cargo build --release
cargo test --release
cargo build --release

All three commands will recompile the entire crate and its dependencies, as if test "invalidated" build.

I have made a repo with a minimum reproducible example: https://github.com/krtab/testltofresh.git

I would second that this is a real-world bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lto Area: link-time optimization A-rebuild-detection Area: rebuild detection and fingerprinting S-triage Status: This issue is waiting on initial triage.
Projects
None yet
Development

No branches or pull requests

3 participants