Skip to content

cargo build --features "X" doesn't update binary mtime when list of features change #15313

Open
@schultetwin1

Description

@schultetwin1

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]

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-build-systemArea: build system integrationA-rebuild-detectionArea: rebuild detection and fingerprintingC-bugCategory: bugS-needs-designStatus: Needs someone to work further on the design for the feature or fix. NOT YET accepted.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions