Skip to content

cargo build doesn't detect file changes #9598

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

Closed
ComicalCache opened this issue Jun 18, 2021 · 6 comments
Closed

cargo build doesn't detect file changes #9598

ComicalCache opened this issue Jun 18, 2021 · 6 comments
Labels
C-bug Category: bug

Comments

@ComicalCache
Copy link

It appears as if cargo doesn't detect file changes when deleting and replacing files.
Running cargo 1.52.0 (6976741 2021-04-21)

  1. cargo new --bin app
  2. cd app
  3. cargo build
    running the generated binary should output "Hello, world!"
  4. rm src/main.rs
  5. echo fn main() { println!("Not Hello, world"); } > main.rs
  6. cp main.rs src/main.rs
  7. cargo build
    this build finishes immediatelly and running the "generated" binary will output "Hello, world!" again

Is this behaviour intendet?

@ComicalCache ComicalCache added the C-bug Category: bug label Jun 18, 2021
@ehuss
Copy link
Contributor

ehuss commented Jun 18, 2021

Thanks for the report! Unfortunately I'm not able to reproduce with the steps provided. Can you provide more information, such as which operating system you are using, which filesystem, are you running this in a strange environment like Docker?

Here's the output that I have:

~/Temp> cargo new --bin app
     Created binary (application) `app` package
~/Temp> cd app
~/Temp/app> cargo build
   Compiling app v0.1.0 (/home/eric/Temp/app)
    Finished dev [unoptimized + debuginfo] target(s) in 0.51s
~/Temp/app> target/debug/app
Hello, world!
~/Temp/app> rm src/main.rs
~/Temp/app> echo 'fn main() { println!("Not Hello, world"); }' > main.rs
~/Temp/app> cp main.rs src/main.rs
~/Temp/app> cargo build
   Compiling app v0.1.0 (/home/eric/Temp/app)
    Finished dev [unoptimized + debuginfo] target(s) in 0.20s
~/Temp/app> target/debug/app
Not Hello, world
~/Temp/app>

In general, cargo uses filesystem mtime timestamps to detect if something needs to be rebuilt. So if you are doing something that causes the timestemp to be in the past, then cargo won't think it has changed.

@ComicalCache
Copy link
Author

ComicalCache commented Jun 18, 2021

I was first encountering this error when building a Docker image, this is the part of my config causing it

FROM rust as builder
# use the global variable
ARG RUST_APP

# create project, copy dependencies and build with default src
RUN USER=root cargo new ${RUST_APP}
WORKDIR /${RUST_APP}
COPY Cargo.toml Cargo.toml
RUN cargo build --release
RUN sha1sum target/release/${RUST_APP}

# delete src, triggers layer with compiled dependencies
RUN rm -r src

# copy program code and rebuild
ADD src src
RUN cargo build --release
RUN sha1sum target/release/${RUST_APP}

comparing the sha sums of the built binaries yields that they are the same, to fix that i added the line

...

# delete src, triggers layer with compiled dependencies
RUN rm -r src
RUN rm target/release/deps/${RUST_APP}*

...

I was able to reproduce it on Windows 10 with

  1. cargo new --bin app
  2. cd app
  3. cargo build
    Again, output of the binary will be "Hello, world!"
  4. del src\main.rs
  5. copy path\to\dif\src src\
  6. cargo build
    Output of the binary didn't change

Edit:

In general, cargo uses filesystem mtime timestamps to detect if something needs to be rebuilt. So if you are doing something that causes the timestemp to be in the past, then cargo won't think it has changed.

I just read this in your answer, this explains it but it was a very confusing and hard to debug bug, at least for me

@ehuss
Copy link
Contributor

ehuss commented Jun 18, 2021

Ah, yea, IIRC when copying into docker, you may need to add a line to run touch src/lib.rs or whatever your source files are, to update the timestamp. And, I think Windows copy preserves the timestamp (whereas unix doesn't do that by default), so if you copy a file in with an older timestamp, it won't rebuild.

I understand that it can be confusing and difficult to understand and debug. There are some issues tracking improvements to deal with this. Primarily #6529 would add change tracking based on file contents, and #2904 is for adding the ability to provide better ways to diagnose why things are or are not rebuilt.

I'm going to close as the problems are well known and tracked in those linked issues.

@pablo-johnson
Copy link

I executed the following command to delete the cache
docker builder prune --filter type=exec.cachemount
in the next built it should take your changes

@wegylexy
Copy link

wegylexy commented Mar 1, 2025

In my case, I'm trying to pre-build dependencies into a cached Docker layer.

FROM rust:alpine AS build
WORKDIR /app
RUN apk add --no-cache build-base openssl-dev
COPY Cargo.toml Cargo.lock ./
RUN mkdir src && \
    echo 'fn main() { println!("Should not see this!") }' > src/main.rs && \
    cargo build -r --locked && \
    rm -rf src
COPY src src
# must `touch` here no matter the copy above is on Windows or Debian
RUN touch src/main.rs
RUN cargo install --path . --locked --offline

FROM alpine:latest AS publish
COPY --from=build /usr/local/cargo/bin/myapp /usr/local/bin/
ENTRYPOINT [ "myapp" ]

Without the touch, the final image will print Should not see this!.

@wegylexy
Copy link

wegylexy commented Mar 1, 2025

Well, after asking GitHub Copilot a few times, I figure that cargo clean -p myapp after the dummy cargo build will also do the trick, i.e. no need to touch.

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

4 participants