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

Cargo not rebuilding with file changed via move #7982

Closed
jrobsonchase opened this issue Mar 10, 2020 · 4 comments
Closed

Cargo not rebuilding with file changed via move #7982

jrobsonchase opened this issue Mar 10, 2020 · 4 comments
Labels
C-bug Category: bug

Comments

@jrobsonchase
Copy link

Problem

I first noticed this when using a "dummy" main.rs in a docker build along with my Cargo.toml/lock to cache the dependencies before building the actual code. It seems that when things are updated via a docker COPY or file move, cargo doesn't notice that they're changed and need to be rebuilt.

Steps

  1. Create a new binary project with cargo new
  2. Copy src/main.rs to src/main.rs.whatever
  3. Change src/main.rs.whatever to greet someone other than "world"
  4. cargo run - outputs "Hello, world!"
  5. mv src/main.rs{.whatever,}
  6. cargo run - outputs "Hello, world!" again, despite main.rs having both a newer mtime and different contents than before

Attaching a script for quick verification of the above steps. Zipped because github doesn't like scripts.

demo.zip

Output of cargo version:

$ cargo version
cargo 1.41.0 (626f0f40e 2019-12-03)

Tested on Arch Linux, rustup show says

active toolchain
----------------

stable-x86_64-unknown-linux-gnu (default)
rustc 1.41.1 (f3e1a954d 2020-02-24)
@jrobsonchase jrobsonchase added the C-bug Category: bug label Mar 10, 2020
@ehuss
Copy link
Contributor

ehuss commented Mar 10, 2020

Thanks for the report. There's an explanation of this here: #7181 (comment).

Using alternate change-detection strategies is tracked in #6529.

Additionally, you may want to read up on #2644. There are some sample Docker files in the comments that illustrate using touch to update mtimes. A number of people have also built tools to assist with building Docker images, such as cargo-wharf (there are links to others in that thread). I've also seen a few bespoke solutions that essentially build a skeleton project.

@ehuss ehuss closed this as completed Mar 10, 2020
@jrobsonchase
Copy link
Author

jrobsonchase commented Mar 10, 2020

Your dummy main.rs has a timestamp newer than the source added by the COPY command (AFAIK, COPY retains the original timestamps). You'll need to add something like touch src/main.rs after copying to ensure that the timestamp is newer than the dummy.

I'm not sure this is the case. (Edit: Well, maybe the case with docker, but not with the mv scenario) With extra stat calls added to the script I provided:

$ bash demo.sh
     Created binary (application) `demo` package
main.rs
  File: src/main.rs
  Size: 45        	Blocks: 8          IO Block: 4096   regular file
Device: 2ah/42d	Inode: 5320505     Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 2000/    josh)   Gid: ( 2000/    josh)
Access: 2020-03-10 16:17:49.030311828 -0400
Modify: 2020-03-10 16:17:49.013645248 -0400
Change: 2020-03-10 16:17:49.013645248 -0400
 Birth: -
fn main() {
    println!("Hello, world!");
}

main.rs.foo
  File: src/main.rs.foo
  Size: 43        	Blocks: 8          IO Block: 4096   regular file
Device: 2ah/42d	Inode: 5321317     Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 2000/    josh)   Gid: ( 2000/    josh)
Access: 2020-03-10 16:17:49.033645143 -0400
Modify: 2020-03-10 16:17:49.033645143 -0400
Change: 2020-03-10 16:17:49.033645143 -0400
 Birth: -
fn main() {
    println!("Hello, foo!");
}

First cargo run
   Compiling demo v0.1.0 (/tmp/demo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.58s
     Running `target/debug/demo`
Hello, world!

Moving main.rs.foo to main.rs

main.rs
  File: src/main.rs
  Size: 43        	Blocks: 8          IO Block: 4096   regular file
Device: 2ah/42d	Inode: 5321317     Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 2000/    josh)   Gid: ( 2000/    josh)
Access: 2020-03-10 16:17:49.040311775 -0400
Modify: 2020-03-10 16:17:49.033645143 -0400
Change: 2020-03-10 16:17:49.640308644 -0400
 Birth: -
fn main() {
    println!("Hello, foo!");
}

Second cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/demo`
Hello, world!

The mtime on the original main.rs is 2020-03-10 16:17:49.013645248, while it's 2020-03-10 16:17:49.033645143 after being updated. It's clearly later during the second cargo run. Unless it's just not sufficiently later?

Another Edit:

Even with adding a sleep between main.rs and main.rs.foo creation so that the mtimes are 2020-03-10 16:27:25.723475371 and 2020-03-10 16:27:30.750108513 respectively causes it to not get rebuilt.

@ehuss
Copy link
Contributor

ehuss commented Mar 10, 2020

Cargo doesn't keep track of the original mtimes of the files. It compares the mtime of the source files to the output files. In your example you have:

  1. src/main.rs at T1
  2. src/main.rs.foo at T2
  3. build. Output is T3
  4. Move src/main.rs.foo to main.rs (which is still T2)
  5. Build again. T2 < T3, so it doesn't think anything has changed since the last build.

@jrobsonchase
Copy link
Author

Ah, I see, my mistake!

At any rate, the touch trick seems to work, and the cargo-wharf thing looks interesting! I'll take a closer look at it 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: bug
Projects
None yet
Development

No branches or pull requests

2 participants