@@ -32,12 +32,13 @@ use rustc_session::output::{collect_crate_types, find_crate_name};
3232use rustc_session:: search_paths:: PathKind ;
3333use rustc_session:: { Limit , Session } ;
3434use rustc_span:: symbol:: { sym, Symbol } ;
35- use rustc_span:: FileName ;
35+ use rustc_span:: { FileName , SourceFileHash , SourceFileHashAlgorithm } ;
3636use rustc_target:: spec:: PanicStrategy ;
3737use rustc_trait_selection:: traits;
3838
3939use std:: any:: Any ;
4040use std:: ffi:: OsString ;
41+ use std:: fs:: File ;
4142use std:: io:: { self , BufWriter , Write } ;
4243use std:: path:: { Path , PathBuf } ;
4344use std:: sync:: { Arc , LazyLock } ;
@@ -420,15 +421,23 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
420421 let result: io:: Result < ( ) > = try {
421422 // Build a list of files used to compile the output and
422423 // write Makefile-compatible dependency rules
423- let mut files: Vec < String > = sess
424+ let mut files: Vec < ( String , u64 , Option < SourceFileHash > ) > = sess
424425 . source_map ( )
425426 . files ( )
426427 . iter ( )
427428 . filter ( |fmap| fmap. is_real_file ( ) )
428429 . 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+ } )
430437 . collect ( ) ;
431438
439+ let checksum_hash_algo = sess. opts . unstable_opts . checksum_hash_algorithm ;
440+
432441 // Account for explicitly marked-to-track files
433442 // (e.g. accessed in proc macros).
434443 let file_depinfo = sess. psess . file_depinfo . borrow ( ) ;
@@ -438,58 +447,115 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
438447 escape_dep_filename ( & file. prefer_local ( ) . to_string ( ) )
439448 } ;
440449
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+
441475 // The entries will be used to declare dependencies beween files in a
442476 // Makefile-like output, so the iteration order does not matter.
443477 #[ 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+ ) ;
446482 files. extend ( extra_tracked_files) ;
447483
448484 // We also need to track used PGO profile files
449485 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+ ) ) ;
451490 }
452491 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+ ) ) ;
454496 }
455497
456498 // Debugger visualizer files
457499 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+ ) ) ;
459504 }
460505
461506 if sess. binary_dep_depinfo ( ) {
462507 if let Some ( ref backend) = sess. opts . unstable_opts . codegen_backend {
463508 if backend. contains ( '.' ) {
464509 // If the backend name contain a `.`, it is the path to an external dynamic
465510 // 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+ ) ) ;
467515 }
468516 }
469517
470518 for & cnum in tcx. crates ( ( ) ) {
471519 let source = tcx. used_crate_source ( cnum) ;
472520 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+ ) ) ;
474525 }
475526 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+ ) ) ;
477531 }
478532 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+ ) ) ;
480537 }
481538 }
482539 }
483540
484541 let write_deps_to_file = |file : & mut dyn Write | -> io:: Result < ( ) > {
485542 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+ ) ?;
487553 }
488554
489555 // Emit a fake target for each input file to the compilation. This
490556 // prevents `make` from spitting out an error if a file is later
491557 // deleted. For more info see #28735
492- for path in files {
558+ for ( path, _file_len , _checksum_hash_algo ) in & files {
493559 writeln ! ( file, "{path}:" ) ?;
494560 }
495561
@@ -513,6 +579,18 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
513579 }
514580 }
515581
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+
516594 Ok ( ( ) )
517595 } ;
518596
0 commit comments