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 build --features "X" doesn't update binary mtime when list of features change #15313

Open
schultetwin1 opened this issue Mar 15, 2025 · 3 comments
Labels
A-build-system Area: build system integration A-rebuild-detection Area: rebuild detection and fingerprinting C-bug Category: bug S-needs-design Status: Needs someone to work further on the design for the feature or fix. NOT YET accepted.

Comments

@schultetwin1
Copy link

Problem

Cargo doesn't appear to be updating the mtime on the binary in the ./target/debug directory when grabbing that file from the cache. This is breaking my using cargo inside a Makefile because the Makefile believes the built binary is older than it actually is.

Steps

  1. Create a repo with the following source

    # Cargo.toml
    [package]
    name = "minrepro"
    version = "0.1.0"
    edition = "2021"
    
    [dependencies]
    
    [features]
    feature_a = []
    feature_b = []
    // src/main.rs
    fn main() {
        #[cfg(feature = "feature_a")]
        println!("Hello, Feature A!");
        #[cfg(feature = "feature_b")]
        println!("Hello, Feature B!");
    
        println!("Hello, world!");
    }
    
    # Makefile to show the problem
    FEATURES :=
    
    ifeq ($(FEATURE),A)
    FEATURES += "feature_a"
    endif
    
    ifeq ($(FEATURE),B)
    FEATURES += "feature_b"
    endif
    
    .PHONY: all FORCE
    
    all: bin
    	./bin
    
    bin: target/debug/minrepro
    	cp target/debug/minrepro bin
    
    target/debug/minrepro: FORCE
    	cargo build --features="$(FEATURES)"
    
  2. Check the current time

    bash$ date
    Fri Mar 14 10:55:00 PM PDT 202
    
  3. Build the crate with feature a

    cargo build --features feature_a
      Compiling minrepro v0.1.0 (/home/matsch/dev/minrepro)
      Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.12s
    
  4. stat the built binary

    bash$ stat ./target/debug/minrepro
    stat ./target/debug/minrepro
    File: ./target/debug/minrepro
    Size: 3946232   	Blocks: 7712       IO Block: 4096   regular file
    Device: 253,1	Inode: 58468456    Links: 2
    Access: (0755/-rwxr-xr-x)  Uid: (1155901/  matsch)   Gid: (89939/primarygroup)
    Access: 2025-03-14 22:55:51.930800853 -0700
    Modify: 2025-03-14 22:55:51.930800853 -0700
    Change: 2025-03-14 22:55:51.938800874 -0700
    Birth: 2025-03-14 22:55:51.874800711 -0700
    
  5. Build the crate with feature b

    cargo build --features feature_b
      Compiling minrepro v0.1.0 (/home/matsch/dev/minrepro)
      Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.12s
    
  6. stat the built binary again

    stat ./target/debug/minrepro
    File: ./target/debug/minrepro
    Size: 3946216   	Blocks: 7712       IO Block: 4096   regular file
    Device: 253,1	Inode: 58470933    Links: 2
    Access: (0755/-rwxr-xr-x)  Uid: (1155901/  matsch)   Gid: (89939/primarygroup)
    Access: 2025-03-14 23:01:12.287611878 -0700
    Modify: 2025-03-14 23:01:12.287611878 -0700
    Change: 2025-03-14 23:01:12.295611898 -0700
    Birth: 2025-03-14 23:01:12.231611736 -0700
    
  7. Build the crate with feature a again

    cargo build --features feature_a
      Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.12s
    
  8. stat the built binary again

    stat ./target/debug/minrepro
    File: ./target/debug/minrepro
    Size: 3946232   	Blocks: 7712       IO Block: 4096   regular file
    Device: 253,1	Inode: 58468456    Links: 2
    Access: (0755/-rwxr-xr-x)  Uid: (1155901/  matsch)   Gid: (89939/primarygroup)
    Access: 2025-03-14 22:55:51.930800853 -0700
    Modify: 2025-03-14 22:55:51.930800853 -0700
    Change: 2025-03-14 23:02:43.063840777 -0700
    Birth: 2025-03-14 22:55:51.874800711 -0700
    

Notice that the "Modify" time is now older than step 5, even though the file on disk has been updated since step "5"

Using the Makefile, I can produce the same issue:

# The first time it works
bash$ FEATURE=B make
cargo build --features=""feature_b""
   Compiling minrepro v0.1.0 (/home/matsch/dev/minrepro)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.13s
cp target/debug/minrepro bin
./bin
Hello, Feature B!
Hello, world!

# Same with feature A
bash$ FEATURE=A make
cargo build --features=""feature_a""
   Compiling minrepro v0.1.0 (/home/matsch/dev/minrepro)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.09s
cp target/debug/minrepro bin
./bin
Hello, Feature A!
Hello, world!

# But now we go back to feature B and it still outputs feature A
# This is because make has determined the `cp` is not needed because the mtime of `./target/debug/minrepro` is older than `bin`
bash$ FEATURE=B make
cargo build --features=""feature_b""
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
./bin
Hello, Feature A!
Hello, world!

Possible Solution(s)

No response

Notes

No response

Version

cargo --version --verbose
cargo 1.85.0 (d73d2caf9 2024-12-31)
release: 1.85.0
commit-hash: d73d2caf9e41a39daf2a8d6ce60ec80bf354d2a7
commit-date: 2024-12-31
host: x86_64-unknown-linux-gnu
libgit2: 1.8.1 (sys:0.19.0 vendored)
libcurl: 8.9.0-DEV (sys:0.4.74+curl-8.9.0 vendored ssl:OpenSSL/1.1.1w)
ssl: OpenSSL 1.1.1w  11 Sep 2023
os: Debian n/a (rodete) [64-bit]
@schultetwin1 schultetwin1 added C-bug Category: bug S-triage Status: This issue is waiting on initial triage. labels Mar 15, 2025
@schultetwin1
Copy link
Author

It looks like this is occurring because cargo hardlinks the file in ./target/debug to the cached binary (code)

@weihanglo weihanglo added A-rebuild-detection Area: rebuild detection and fingerprinting A-build-system Area: build system integration labels Mar 15, 2025
@weihanglo
Copy link
Member

Thanks for the detailed report and the reproducible steps!

This sounds like a variant of #8649. There are some solutions provided in #8649 (comment).

Apart from that, Cargo has an unstable feature -Zchecksum-freshness using file checksum replacing mtime. Depending on mtime might be a bit more unreliable when that is stabilized.

@weihanglo weihanglo added S-needs-design Status: Needs someone to work further on the design for the feature or fix. NOT YET accepted. and removed S-triage Status: This issue is waiting on initial triage. labels Mar 15, 2025
@schultetwin1
Copy link
Author

This sounds like a variant of #8649.

That looks right to me as well! Sorry I missed this originally.

There are some solutions provided in #8649 (comment).

Thanks! My current solution is to change the Makefile to cp the output only if the destination and source sha1sum are different. I also like this idea provided by @ehuss, "Cargo could be changed (maybe with an option?) to always update the mtime of the outputs when it runs" but I'd be concerned this would break something else I'm not thinking about.

Depending on mtime might be a bit more unreliable when that is stabilized

Good to know, thanks for the heads up!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-build-system Area: build system integration A-rebuild-detection Area: rebuild detection and fingerprinting C-bug Category: bug S-needs-design Status: Needs someone to work further on the design for the feature or fix. NOT YET accepted.
Projects
None yet
Development

No branches or pull requests

2 participants