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

Parse # env-dep directives in dep-info files #8421

Merged
merged 6 commits into from
Jun 30, 2020

Conversation

alexcrichton
Copy link
Member

This commit updates Cargo's parsing of rustc's dep-info files to account
for changes made upstream in rust-lang/rust#71858. This means that if
env! or option_env! is used in crate files Cargo will correctly
rebuild the crate if the env var changes.

Closes #8417

@rust-highfive
Copy link

r? @ehuss

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 26, 2020
@alexcrichton
Copy link
Member Author

Note that this'll fail CI until we get a nightly tonight, but I was testing with a toolchain that has support for # env-dep so I think everything should otherwise be working.

@alexcrichton
Copy link
Member Author

Ok I've pushed up a commit which fixes some dep-info parsing bits in the test suite, but this actually uncovered an unfortunate behavior that I'm not sure what to do about:

#[cargo_test]
fn env_build_script_no_rebuild() {
    // Only nightly has support in dep-info files for this
    if !cargo_test_support::is_nightly() {
        return;
    }
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                version = "0.1.0"
            "#,
        )
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-env=FOO=bar");
                }
            "#,
        )
        .file(
            "src/main.rs",
            r#"
                fn main() {
                    println!("{:?}", env!("FOO"));
                }
            "#,
        )
        .build();

    p.cargo("build").run();
    p.cargo("build").with_stderr("[FINISHED] [..]").run();
}

That test fails because it rebuilds. The problem is that Cargo sees the previous compilation read the env var FOO, but it's reading the value of FOO from Cargo's own environment, which misses how this env var is defined by a build script. A similar issue is happening in the target dir renaming test because the value of OUT_DIR is changing, and that's not defined in Cargo's process.

Cargo can't really predict the value of env vars coming from build scripts, so I guess it just has to ignore them? We'd have to keep a list of "these env vars are defined by build scripts" from the previous compilation and use that to filter the env vars to check in Cargo itself.

I'll try to think about this and see if there's something better. Handling OUT_DIR I think will also be a bit tricky.

@Mark-Simulacrum
Copy link
Member

Well, the behavior I would expect is that we don't necessarily rebuild the crate after re-running the build script -- I think today that's never the case, though, so would be "new feature" in some sense. I think I recall an issue about this but can't find it today.

I think that sort of thing is pretty hard given Cargo's architecture today -- IIRC, we need to upfront decide everything we're planning to build. I guess in theory the crate could be a no-op build somewhat hackily (the cargo 'step' runs but compiler isn't invoked).

This commit updates Cargo's parsing of rustc's dep-info files to account
for changes made upstream in rust-lang/rust#71858. This means that if
`env!` or `option_env!` is used in crate files Cargo will correctly
rebuild the crate if the env var changes.

Closes rust-lang#8417
@alexcrichton
Copy link
Member Author

Ok I've pushed up a commit I think addresses the issue. I figured out an easy-ish way to do it because translate_dep_info happens so late in the process.

FWIW we unconditionally rebuild the crate if a build script is rerun, we definitely don't have any red/green style tracking like the compiler does where if the build script produces the same output we don't rebuild any crates. (same for if you recompile a crate and it produces byte-for-byte the same output we still build everything else)

The main problem I was imagining is that we can't even predict what env vars a build script will set. At the point we translate rustc's dep info to Cargo's dep info, however, we have a ProcessBuilder which contains all specific env vars to just that compilation which we can exclude from rustc's set of recorded env vars used during the compile. That should limit us precisely to the set of env vars used that weren't defined by Cargo, which is what we're interested in tracking. (the comment inline has more info to this)

Copy link
Contributor

@ehuss ehuss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking it might be a good idea to update the metadata version since this changes the format of the dep-info file. It should be backwards-compatible since the new cargo ignores parse errors, but older versions of cargo do not (it fails with dep-info invalid error). Not strictly necessary since switching to an older nightly is unusual, but might be worth avoiding.

There are a few comments that I'd like to see updated with the new behavior. Ones that I see (github won't let me annotate them):

  • A brief note in the module-docs section "dep-info files" about env var support.
  • LocalFingerprint::find_stale_item "a stale file or env var".
  • parse_dep_info "a list of paths and env vars"

src/cargo/core/compiler/fingerprint.rs Show resolved Hide resolved
src/cargo/core/compiler/fingerprint.rs Outdated Show resolved Hide resolved
tests/testsuite/freshness.rs Outdated Show resolved Hide resolved
tests/testsuite/freshness.rs Outdated Show resolved Hide resolved
src/cargo/core/compiler/fingerprint.rs Outdated Show resolved Hide resolved
Ok(Some(paths))
let info = match OnDiskDepInfo::parse(&data) {
Some(info) => info,
None => return Ok(None),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this at least log a warning that it failed to parse the dep-info file? I assume this would only happen if the file is corrupt (or in some different format?). I assume you changed this so if the format is changed again in the future, cargo will just silently rebuild (which seems like the correct approach).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm actually I misinterpreted the previous code. I thought the previous iteration also ignored parsing errors but it looks like it only ignores I/O and/or not present errors. I do think, though, that it's reasonable to ignore corrupt files here since we'll rewrite them later anyway.

@alexcrichton
Copy link
Member Author

Ok updated!

@ehuss
Copy link
Contributor

ehuss commented Jun 29, 2020

Not sure if you saw the note about changing the version in compute_metadata. I feel it would be a little safer to change that.

@alexcrichton
Copy link
Member Author

Er oops sorry I saw that and then completely forgot to add it, I'll look into escaping, I don't know what kind of escaping rustc does...

@alexcrichton
Copy link
Member Author

Ok read up on the escaping rustc does and am now matching that here too

@ehuss
Copy link
Contributor

ehuss commented Jun 30, 2020

Thanks, looks good!

@bors r+

@bors
Copy link
Collaborator

bors commented Jun 30, 2020

📌 Commit 0750a6f has been approved by ehuss

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 30, 2020
@bors
Copy link
Collaborator

bors commented Jun 30, 2020

⌛ Testing commit 0750a6f with merge 77b4058...

@bors
Copy link
Collaborator

bors commented Jun 30, 2020

☀️ Test successful - checks-azure
Approved by: ehuss
Pushing 77b4058 to master...

@bors bors merged commit 77b4058 into rust-lang:master Jun 30, 2020
Manishearth added a commit to Manishearth/rust that referenced this pull request Jul 2, 2020
Update cargo

## cargo
10 commits in c26576f9adddd254b3dd63aecba176434290a9f6..305eaf0dc5f5a38d6e8041319c2da95b71cf6a4a
2020-06-23 16:21:21 +0000 to 2020-06-30 14:16:08 +0000
- Update core-foundation requirement from 0.7.0 to 0.9.0 (rust-lang/cargo#8432)
- Parse `# env-dep` directives in dep-info files (rust-lang/cargo#8421)
- Move string interning to util (rust-lang/cargo#8419)
- Expose built cdylib artifacts in the Compilation structure (rust-lang/cargo#8418)
- Remove unused serde_derive dependency from the crates.io crate (rust-lang/cargo#8416)
- Remove unused remove_dir_all dependency (rust-lang/cargo#8412)
- Improve git error messages a bit (rust-lang/cargo#8409)
- Improve the description of Config.home_path (rust-lang/cargo#8408)
- Improve support for non-`master` main branches (rust-lang/cargo#8364)
- Document that OUT_DIR in JSON messages is an absolute path (rust-lang/cargo#8403)

## rls
2020-06-19 15:36:00 +0200 to 2020-06-30 23:34:52 +0200
- Update cargo (rust-lang/rls#1686)
bors added a commit to rust-lang-ci/rust that referenced this pull request Jul 3, 2020
Update cargo, rls

## cargo
14 commits in c26576f9adddd254b3dd63aecba176434290a9f6..fede83ccf973457de319ba6fa0e36ead454d2e20
2020-06-23 16:21:21 +0000 to 2020-07-02 21:51:34 +0000
- Fix overflow error on 32-bit. (rust-lang/cargo#8446)
- Exclude the target directory from backups using CACHEDIR.TAG (rust-lang/cargo#8378)
- CONTRIBUTING.md: Link to Zulip rather than Discord (rust-lang/cargo#8436)
- Update built-in help for features (rust-lang/cargo#8433)
- Update core-foundation requirement from 0.7.0 to 0.9.0 (rust-lang/cargo#8432)
- Parse `# env-dep` directives in dep-info files (rust-lang/cargo#8421)
- Move string interning to util (rust-lang/cargo#8419)
- Expose built cdylib artifacts in the Compilation structure (rust-lang/cargo#8418)
- Remove unused serde_derive dependency from the crates.io crate (rust-lang/cargo#8416)
- Remove unused remove_dir_all dependency (rust-lang/cargo#8412)
- Improve git error messages a bit (rust-lang/cargo#8409)
- Improve the description of Config.home_path (rust-lang/cargo#8408)
- Improve support for non-`master` main branches (rust-lang/cargo#8364)
- Document that OUT_DIR in JSON messages is an absolute path (rust-lang/cargo#8403)

## rls
2020-06-19 15:36:00 +0200 to 2020-06-30 23:34:52 +0200
- Update cargo (rust-lang/rls#1686)
Manishearth added a commit to Manishearth/rust that referenced this pull request Jul 22, 2020
…ulacrum

build: Remove unnecessary `cargo:rerun-if-env-changed` annotations

... and a couple of related cleanups.

rustc and cargo now track the majority of env var dependencies automatically (rust-lang/cargo#8421), so the annotations are no longer necessary.
Manishearth added a commit to Manishearth/rust that referenced this pull request Jul 22, 2020
…ulacrum

build: Remove unnecessary `cargo:rerun-if-env-changed` annotations

... and a couple of related cleanups.

rustc and cargo now track the majority of env var dependencies automatically (rust-lang/cargo#8421), so the annotations are no longer necessary.
Manishearth added a commit to Manishearth/rust that referenced this pull request Jul 22, 2020
…ulacrum

build: Remove unnecessary `cargo:rerun-if-env-changed` annotations

... and a couple of related cleanups.

rustc and cargo now track the majority of env var dependencies automatically (rust-lang/cargo#8421), so the annotations are no longer necessary.
Manishearth added a commit to Manishearth/rust that referenced this pull request Jul 22, 2020
…ulacrum

build: Remove unnecessary `cargo:rerun-if-env-changed` annotations

... and a couple of related cleanups.

rustc and cargo now track the majority of env var dependencies automatically (rust-lang/cargo#8421), so the annotations are no longer necessary.
@alexcrichton alexcrichton deleted the read-env-dep branch July 29, 2020 17:49
// that's used for code generation but this is technically buggy where if
// you write a binary that does `println!("{}", env!("OUT_DIR"))` we won't
// recompile that if you move the target directory. Hopefully that's not too
// bad of an issue for now...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alecmocatta I think this comment here exactly describes your issue https://github.com/rust-lang/rust/issues/76511 ;)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I believe it does, thanks for finding this @RalfJung!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Use # env-dep annotations in .d files produced by rustc to track dependencies on environment variables
7 participants