-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Closed
Labels
A-build-scriptsArea: build.rs scriptsArea: build.rs scriptsA-rebuild-detectionArea: rebuild detection and fingerprintingArea: rebuild detection and fingerprintingC-bugCategory: bugCategory: bug
Description
There is a scenario where cargo fails to rebuild when the execution of a build script is interrupted (such as hitting ctrl-c). There are a variety of ways this can happen, the test below illustrates one way.
The fundamental problem is that the fingerprint does not track enough information about the execution of a build script as a dependency. #6720 added tracking the invoked.timestamp
file, but that is not sufficient.
I've been pondering various ways to fix this, but not loving the options. I would be interested if anyone has any more ideas. Bonus points if both this and #6733 can be fixed. Some options:
- Build script fingerprint of registry dependencies is not tracked in fingerprint. #6733 mentions adding the info from
build_script_local_fingerprints
, but there are some complications with updating that after the build is done (it would need to do everything thatprepare_build_cmd
does, too). - Add another file that is written in the fingerprint dir that tracks the completion of running the build script, perhaps with a sequence number bumped each time it is run.
- When the build script starts, write
invoked.timestamp.start
(and deleteinvoked.timestamp
) and then when the build script succeeds, rename it toinvoked.timestamp
. I think this should work, but I'm not sure. - (Crazy) Switch to a database for fingerprint tracking to make it easier to track dependencies.
Example
(This currently fails on the last line where the build succeeds when it should fail.)
#[test]
fn script_fails_stay_dirty() {
let p = project()
.file(
"build.rs",
r#"
mod helper;
fn main() {
println!("cargo:rerun-if-changed=build.rs");
helper::doit();
}
"#,
)
.file("helper.rs", "pub fn doit() {}")
.file("src/lib.rs", "")
.build();
p.cargo("build").run();
p.change_file("helper.rs", r#"pub fn doit() {panic!("Crash!");}"#);
p.cargo("build")
.with_stderr_contains("[..]Crash![..]")
.with_status(101)
.run();
// There was a bug where this second call would be "fresh".
p.cargo("build")
.with_stderr_contains("[..]Crash![..]")
.with_status(101)
.run();
}
Metadata
Metadata
Assignees
Labels
A-build-scriptsArea: build.rs scriptsArea: build.rs scriptsA-rebuild-detectionArea: rebuild detection and fingerprintingArea: rebuild detection and fingerprintingC-bugCategory: bugCategory: bug
Type
Projects
Milestone
Relationships
Development
Select code repository
Activity
alexcrichton commentedon Mar 21, 2019
Jeez we just can't seem to get this right :(. I really would start seriously considering larger scale revamps because it's be clear that ever since inception we haven't been able to ever produce a bug-free system where incremental works correctly in all cases...
Is the problem here that there's still a file on the filesystem which indicates a successful run, and so during the failing step above Cargo correctly realizes it doesn't need to rebuild the build script itself but incorrectly reuses the old successful output assuming the new binary succeeded?
I sort of forget how this is solved for crates, but I vaguely remember us deleting files that is recognized specially (this could be totally wrong though). Do you recall off the top of your head how that works for normal crates?
ehuss commentedon Mar 21, 2019
Correct. The build script fingerprint only tracks the
rerun-if
statements, and this example it is literally justbuild.rs
. Thinking about it more, perhaps it is sufficient to add the fingerprint of the compilation of the build script? I'm going to experiment with that, it might be sufficient. I think the issue in #6720 would still broken here, though.For context, this was discovered by @eddyb working on the gll crate which has a number of modules in the build script and he was hitting the OOM killer (I think).
gll
could addrerun-if-changed
lines for each file, but I don't think it is reasonable to require that for normal rust modules.A normal crate would catch this from the dep-info file. The running of a build script is the odd one out. It requires build script authors to be extremely diligent in tracking all inputs, and I think we can ease that a little. I suspect I'm missing something, though.
alexcrichton commentedon Mar 21, 2019
Hm ok, so it sounds like the build script execution is buggily not tracking the build script itself. In that one of the inputs to the build script execution should be the binary of the build script itself, which we should recognize has changed from the previous successful run which triggers a run until it succeeds.
I do remember we fixed a number of issues like this by adding dependency edges from packages to their dependencies (in the fingerprints), so maybe we're just missing that for build script execution?
Auto merge of #6782 - ehuss:build-script-fingerprint-fixes, r=alexcri…