187
187
//! See the `A-rebuild-detection` flag on the issue tracker for more:
188
188
//! <https://github.com/rust-lang/cargo/issues?q=is%3Aissue+is%3Aopen+label%3AA-rebuild-detection>
189
189
190
+ use std:: collections:: HashMap ;
190
191
use std:: env;
191
192
use std:: fs;
192
193
use std:: hash:: { self , Hasher } ;
@@ -322,6 +323,7 @@ struct DepFingerprint {
322
323
pkg_id : u64 ,
323
324
name : String ,
324
325
public : bool ,
326
+ only_requires_rmeta : bool ,
325
327
fingerprint : Arc < Fingerprint > ,
326
328
}
327
329
@@ -395,17 +397,15 @@ enum FsStatus {
395
397
/// unit needs to subsequently be recompiled.
396
398
Stale ,
397
399
398
- /// This unit is up-to-date, it does not need to be recompiled. If there are
399
- /// any outputs then the `FileTime` listed here is the minimum of all their
400
- /// mtimes. This is then later used to see if a unit is newer than one of
401
- /// its dependants, causing the dependant to be recompiled.
402
- UpToDate ( Option < FileTime > ) ,
400
+ /// This unit is up-to-date. All outputs and their corresponding mtime are
401
+ /// listed in the payload here for other dependencies to compare against.
402
+ UpToDate { mtimes : HashMap < PathBuf , FileTime > } ,
403
403
}
404
404
405
405
impl FsStatus {
406
406
fn up_to_date ( & self ) -> bool {
407
407
match self {
408
- FsStatus :: UpToDate ( _ ) => true ,
408
+ FsStatus :: UpToDate { .. } => true ,
409
409
FsStatus :: Stale => false ,
410
410
}
411
411
}
@@ -442,6 +442,7 @@ impl<'de> Deserialize<'de> for DepFingerprint {
442
442
pkg_id,
443
443
name,
444
444
public,
445
+ only_requires_rmeta : false ,
445
446
fingerprint : Arc :: new ( Fingerprint {
446
447
memoized_hash : Mutex :: new ( Some ( hash) ) ,
447
448
..Fingerprint :: new ( )
@@ -753,51 +754,71 @@ impl Fingerprint {
753
754
) -> CargoResult < ( ) > {
754
755
assert ! ( !self . fs_status. up_to_date( ) ) ;
755
756
757
+ let mut mtimes = HashMap :: new ( ) ;
758
+
756
759
// Get the `mtime` of all outputs. Optionally update their mtime
757
760
// afterwards based on the `mtime_on_use` flag. Afterwards we want the
758
761
// minimum mtime as it's the one we'll be comparing to inputs and
759
762
// dependencies.
760
- let status = self
761
- . outputs
762
- . iter ( )
763
- . map ( |f| {
764
- let mtime = paths:: mtime ( f) . ok ( ) ;
765
- if mtime_on_use {
766
- let t = FileTime :: from_system_time ( SystemTime :: now ( ) ) ;
767
- drop ( filetime:: set_file_times ( f, t, t) ) ;
763
+ for output in self . outputs . iter ( ) {
764
+ let mtime = match paths:: mtime ( output) {
765
+ Ok ( mtime) => mtime,
766
+
767
+ // This path failed to report its `mtime`. It probably doesn't
768
+ // exists, so leave ourselves as stale and bail out.
769
+ Err ( e) => {
770
+ log:: debug!( "failed to get mtime of {:?}: {}" , output, e) ;
771
+ return Ok ( ( ) ) ;
768
772
}
769
- mtime
770
- } )
771
- . min ( ) ;
773
+ } ;
774
+ if mtime_on_use {
775
+ let t = FileTime :: from_system_time ( SystemTime :: now ( ) ) ;
776
+ filetime:: set_file_times ( output, t, t) ?;
777
+ }
778
+ assert ! ( mtimes. insert( output. clone( ) , mtime) . is_none( ) ) ;
779
+ }
780
+
781
+ let max_mtime = match mtimes. values ( ) . max ( ) {
782
+ Some ( mtime) => mtime,
772
783
773
- let mtime = match status {
774
784
// We had no output files. This means we're an overridden build
775
785
// script and we're just always up to date because we aren't
776
786
// watching the filesystem.
777
787
None => {
778
- self . fs_status = FsStatus :: UpToDate ( None ) ;
788
+ self . fs_status = FsStatus :: UpToDate { mtimes } ;
779
789
return Ok ( ( ) ) ;
780
790
}
781
-
782
- // At least one path failed to report its `mtime`. It probably
783
- // doesn't exists, so leave ourselves as stale and bail out.
784
- Some ( None ) => return Ok ( ( ) ) ,
785
-
786
- // All files successfully reported an `mtime`, and we've got the
787
- // minimum one, so let's keep going with that.
788
- Some ( Some ( mtime) ) => mtime,
789
791
} ;
790
792
791
793
for dep in self . deps . iter ( ) {
792
- let dep_mtime = match dep. fingerprint . fs_status {
794
+ let dep_mtimes = match & dep. fingerprint . fs_status {
795
+ FsStatus :: UpToDate { mtimes } => mtimes,
793
796
// If our dependency is stale, so are we, so bail out.
794
797
FsStatus :: Stale => return Ok ( ( ) ) ,
798
+ } ;
795
799
796
- // If our dependencies is up to date and has no filesystem
797
- // interactions, then we can move on to the next dependency.
798
- FsStatus :: UpToDate ( None ) => continue ,
799
-
800
- FsStatus :: UpToDate ( Some ( mtime) ) => mtime,
800
+ // If our dependency edge only requires the rmeta fiel to be present
801
+ // then we only need to look at that one output file, otherwise we
802
+ // need to consider all output files to see if we're out of date.
803
+ let dep_mtime = if dep. only_requires_rmeta {
804
+ dep_mtimes
805
+ . iter ( )
806
+ . filter_map ( |( path, mtime) | {
807
+ if path. extension ( ) . and_then ( |s| s. to_str ( ) ) == Some ( "rmeta" ) {
808
+ Some ( mtime)
809
+ } else {
810
+ None
811
+ }
812
+ } )
813
+ . next ( )
814
+ . expect ( "failed to find rmeta" )
815
+ } else {
816
+ match dep_mtimes. values ( ) . max ( ) {
817
+ Some ( mtime) => mtime,
818
+ // If our dependencies is up to date and has no filesystem
819
+ // interactions, then we can move on to the next dependency.
820
+ None => continue ,
821
+ }
801
822
} ;
802
823
803
824
// If the dependency is newer than our own output then it was
@@ -807,7 +828,8 @@ impl Fingerprint {
807
828
// Note that this comparison should probably be `>=`, not `>`, but
808
829
// for a discussion of why it's `>` see the discussion about #5918
809
830
// below in `find_stale`.
810
- if dep_mtime > mtime {
831
+ if dep_mtime > max_mtime {
832
+ log:: info!( "dependency on `{}` is newer than we are" , dep. name) ;
811
833
return Ok ( ( ) ) ;
812
834
}
813
835
}
@@ -824,7 +846,7 @@ impl Fingerprint {
824
846
}
825
847
826
848
// Everything was up to date! Record such.
827
- self . fs_status = FsStatus :: UpToDate ( Some ( mtime ) ) ;
849
+ self . fs_status = FsStatus :: UpToDate { mtimes } ;
828
850
829
851
Ok ( ( ) )
830
852
}
@@ -856,6 +878,7 @@ impl hash::Hash for Fingerprint {
856
878
name,
857
879
public,
858
880
fingerprint,
881
+ only_requires_rmeta : _,
859
882
} in deps
860
883
{
861
884
pkg_id. hash ( h) ;
@@ -929,6 +952,7 @@ impl DepFingerprint {
929
952
name,
930
953
public,
931
954
fingerprint,
955
+ only_requires_rmeta : cx. only_requires_rmeta ( parent, dep) ,
932
956
} )
933
957
}
934
958
}
0 commit comments