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