@@ -31,12 +31,13 @@ use rustc_session::output::filename_for_input;
31
31
use rustc_session:: search_paths:: PathKind ;
32
32
use rustc_session:: { Limit , Session } ;
33
33
use rustc_span:: symbol:: { sym, Symbol } ;
34
- use rustc_span:: FileName ;
34
+ use rustc_span:: { FileName , SourceFileHash , SourceFileHashAlgorithm } ;
35
35
use rustc_target:: spec:: PanicStrategy ;
36
36
use rustc_trait_selection:: traits;
37
37
38
38
use std:: any:: Any ;
39
39
use std:: ffi:: OsString ;
40
+ use std:: fs:: File ;
40
41
use std:: io:: { self , BufWriter , Write } ;
41
42
use std:: path:: { Path , PathBuf } ;
42
43
use std:: sync:: LazyLock ;
@@ -417,15 +418,23 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
417
418
let result: io:: Result < ( ) > = try {
418
419
// Build a list of files used to compile the output and
419
420
// write Makefile-compatible dependency rules
420
- let mut files: Vec < String > = sess
421
+ let mut files: Vec < ( String , u64 , Option < SourceFileHash > ) > = sess
421
422
. source_map ( )
422
423
. files ( )
423
424
. iter ( )
424
425
. filter ( |fmap| fmap. is_real_file ( ) )
425
426
. filter ( |fmap| !fmap. is_imported ( ) )
426
- . map ( |fmap| escape_dep_filename ( & fmap. name . prefer_local ( ) . to_string ( ) ) )
427
+ . map ( |fmap| {
428
+ (
429
+ escape_dep_filename ( & fmap. name . prefer_local ( ) . to_string ( ) ) ,
430
+ fmap. source_len . 0 as u64 ,
431
+ fmap. checksum_hash ,
432
+ )
433
+ } )
427
434
. collect ( ) ;
428
435
436
+ let checksum_hash_algo = sess. opts . unstable_opts . checksum_hash_algorithm ;
437
+
429
438
// Account for explicitly marked-to-track files
430
439
// (e.g. accessed in proc macros).
431
440
let file_depinfo = sess. psess . file_depinfo . borrow ( ) ;
@@ -435,58 +444,115 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
435
444
escape_dep_filename ( & file. prefer_local ( ) . to_string ( ) )
436
445
} ;
437
446
447
+ fn hash_iter_files < P : AsRef < Path > > (
448
+ it : impl Iterator < Item = P > ,
449
+ checksum_hash_algo : Option < SourceFileHashAlgorithm > ,
450
+ ) -> impl Iterator < Item = ( P , u64 , Option < SourceFileHash > ) > {
451
+ it. map ( move |path| {
452
+ match checksum_hash_algo. and_then ( |algo| {
453
+ File :: open ( path. as_ref ( ) )
454
+ . and_then ( |mut file| {
455
+ SourceFileHash :: new ( algo, & mut file) . map ( |h| ( file, h) )
456
+ } )
457
+ . and_then ( |( file, h) | file. metadata ( ) . map ( |m| ( m. len ( ) , h) ) )
458
+ . map_err ( |e| {
459
+ tracing:: error!(
460
+ "failed to compute checksum, omitting it from dep-info {} {e}" ,
461
+ path. as_ref( ) . display( )
462
+ )
463
+ } )
464
+ . ok ( )
465
+ } ) {
466
+ Some ( ( file_len, checksum) ) => ( path, file_len, Some ( checksum) ) ,
467
+ None => ( path, 0 , None ) ,
468
+ }
469
+ } )
470
+ }
471
+
438
472
// The entries will be used to declare dependencies beween files in a
439
473
// Makefile-like output, so the iteration order does not matter.
440
474
#[ allow( rustc:: potential_query_instability) ]
441
- let extra_tracked_files =
442
- file_depinfo. iter ( ) . map ( |path_sym| normalize_path ( PathBuf :: from ( path_sym. as_str ( ) ) ) ) ;
475
+ let extra_tracked_files = hash_iter_files (
476
+ file_depinfo. iter ( ) . map ( |path_sym| normalize_path ( PathBuf :: from ( path_sym. as_str ( ) ) ) ) ,
477
+ checksum_hash_algo,
478
+ ) ;
443
479
files. extend ( extra_tracked_files) ;
444
480
445
481
// We also need to track used PGO profile files
446
482
if let Some ( ref profile_instr) = sess. opts . cg . profile_use {
447
- files. push ( normalize_path ( profile_instr. as_path ( ) . to_path_buf ( ) ) ) ;
483
+ files. extend ( hash_iter_files (
484
+ iter:: once ( normalize_path ( profile_instr. as_path ( ) . to_path_buf ( ) ) ) ,
485
+ checksum_hash_algo,
486
+ ) ) ;
448
487
}
449
488
if let Some ( ref profile_sample) = sess. opts . unstable_opts . profile_sample_use {
450
- files. push ( normalize_path ( profile_sample. as_path ( ) . to_path_buf ( ) ) ) ;
489
+ files. extend ( hash_iter_files (
490
+ iter:: once ( normalize_path ( profile_sample. as_path ( ) . to_path_buf ( ) ) ) ,
491
+ checksum_hash_algo,
492
+ ) ) ;
451
493
}
452
494
453
495
// Debugger visualizer files
454
496
for debugger_visualizer in tcx. debugger_visualizers ( LOCAL_CRATE ) {
455
- files. push ( normalize_path ( debugger_visualizer. path . clone ( ) . unwrap ( ) ) ) ;
497
+ files. extend ( hash_iter_files (
498
+ iter:: once ( normalize_path ( debugger_visualizer. path . clone ( ) . unwrap ( ) ) ) ,
499
+ checksum_hash_algo,
500
+ ) ) ;
456
501
}
457
502
458
503
if sess. binary_dep_depinfo ( ) {
459
504
if let Some ( ref backend) = sess. opts . unstable_opts . codegen_backend {
460
505
if backend. contains ( '.' ) {
461
506
// If the backend name contain a `.`, it is the path to an external dynamic
462
507
// library. If not, it is not a path.
463
- files. push ( backend. to_string ( ) ) ;
508
+ files. extend ( hash_iter_files (
509
+ iter:: once ( backend. to_string ( ) ) ,
510
+ checksum_hash_algo,
511
+ ) ) ;
464
512
}
465
513
}
466
514
467
515
for & cnum in tcx. crates ( ( ) ) {
468
516
let source = tcx. used_crate_source ( cnum) ;
469
517
if let Some ( ( path, _) ) = & source. dylib {
470
- files. push ( escape_dep_filename ( & path. display ( ) . to_string ( ) ) ) ;
518
+ files. extend ( hash_iter_files (
519
+ iter:: once ( escape_dep_filename ( & path. display ( ) . to_string ( ) ) ) ,
520
+ checksum_hash_algo,
521
+ ) ) ;
471
522
}
472
523
if let Some ( ( path, _) ) = & source. rlib {
473
- files. push ( escape_dep_filename ( & path. display ( ) . to_string ( ) ) ) ;
524
+ files. extend ( hash_iter_files (
525
+ iter:: once ( escape_dep_filename ( & path. display ( ) . to_string ( ) ) ) ,
526
+ checksum_hash_algo,
527
+ ) ) ;
474
528
}
475
529
if let Some ( ( path, _) ) = & source. rmeta {
476
- files. push ( escape_dep_filename ( & path. display ( ) . to_string ( ) ) ) ;
530
+ files. extend ( hash_iter_files (
531
+ iter:: once ( escape_dep_filename ( & path. display ( ) . to_string ( ) ) ) ,
532
+ checksum_hash_algo,
533
+ ) ) ;
477
534
}
478
535
}
479
536
}
480
537
481
538
let write_deps_to_file = |file : & mut dyn Write | -> io:: Result < ( ) > {
482
539
for path in out_filenames {
483
- writeln ! ( file, "{}: {}\n " , path. display( ) , files. join( " " ) ) ?;
540
+ writeln ! (
541
+ file,
542
+ "{}: {}\n " ,
543
+ path. display( ) ,
544
+ files
545
+ . iter( )
546
+ . map( |( path, _file_len, _checksum_hash_algo) | path. as_str( ) )
547
+ . intersperse( " " )
548
+ . collect:: <String >( )
549
+ ) ?;
484
550
}
485
551
486
552
// Emit a fake target for each input file to the compilation. This
487
553
// prevents `make` from spitting out an error if a file is later
488
554
// deleted. For more info see #28735
489
- for path in files {
555
+ for ( path, _file_len , _checksum_hash_algo ) in & files {
490
556
writeln ! ( file, "{path}:" ) ?;
491
557
}
492
558
@@ -510,6 +576,18 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
510
576
}
511
577
}
512
578
579
+ // If caller requested this information, add special comments about source file checksums.
580
+ // These are not necessarily the same checksums as was used in the debug files.
581
+ if sess. opts . unstable_opts . checksum_hash_algorithm ( ) . is_some ( ) {
582
+ for ( path, file_len, checksum_hash) in
583
+ files. iter ( ) . filter_map ( |( path, file_len, hash_algo) | {
584
+ hash_algo. map ( |hash_algo| ( path, file_len, hash_algo) )
585
+ } )
586
+ {
587
+ writeln ! ( file, "# checksum:{checksum_hash} file_len:{file_len} {path}" ) ?;
588
+ }
589
+ }
590
+
513
591
Ok ( ( ) )
514
592
} ;
515
593
0 commit comments