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