@@ -32,8 +32,8 @@ use rustc_session::cstore::Untracked;
3232use rustc_session:: output:: { collect_crate_types, filename_for_input, find_crate_name} ;
3333use rustc_session:: search_paths:: PathKind ;
3434use rustc_session:: { Limit , Session } ;
35- use rustc_span:: FileName ;
3635use rustc_span:: symbol:: { Symbol , sym} ;
36+ use rustc_span:: { FileName , SourceFileHash , SourceFileHashAlgorithm } ;
3737use rustc_target:: spec:: PanicStrategy ;
3838use rustc_trait_selection:: traits;
3939use tracing:: { info, instrument} ;
@@ -417,15 +417,23 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
417417 let result: io:: Result < ( ) > = try {
418418 // Build a list of files used to compile the output and
419419 // write Makefile-compatible dependency rules
420- let mut files: Vec < String > = sess
420+ let mut files: Vec < ( String , u64 , Option < SourceFileHash > ) > = sess
421421 . source_map ( )
422422 . files ( )
423423 . iter ( )
424424 . filter ( |fmap| fmap. is_real_file ( ) )
425425 . 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+ } )
427433 . collect ( ) ;
428434
435+ let checksum_hash_algo = sess. opts . unstable_opts . checksum_hash_algorithm ;
436+
429437 // Account for explicitly marked-to-track files
430438 // (e.g. accessed in proc macros).
431439 let file_depinfo = sess. psess . file_depinfo . borrow ( ) ;
@@ -437,56 +445,132 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
437445
438446 // The entries will be used to declare dependencies between files in a
439447 // 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+
440473 #[ 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+ ) ;
443478 files. extend ( extra_tracked_files) ;
444479
445480 // We also need to track used PGO profile files
446481 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+ ) ) ;
448486 }
449487 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+ ) ) ;
451492 }
452493
453494 // Debugger visualizer files
454495 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+ ) ) ;
456500 }
457501
458502 if sess. binary_dep_depinfo ( ) {
459503 if let Some ( ref backend) = sess. opts . unstable_opts . codegen_backend {
460504 if backend. contains ( '.' ) {
461505 // If the backend name contain a `.`, it is the path to an external dynamic
462506 // 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+ ) ) ;
464511 }
465512 }
466513
467514 for & cnum in tcx. crates ( ( ) ) {
468515 let source = tcx. used_crate_source ( cnum) ;
469516 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+ ) ) ;
471521 }
472522 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+ ) ) ;
474527 }
475528 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+ ) ) ;
477533 }
478534 }
479535 }
480536
481537 let write_deps_to_file = |file : & mut dyn Write | -> io:: Result < ( ) > {
482538 for path in out_filenames {
483- writeln ! ( file, "{}: {}\n " , path. display( ) , files. join( " " ) ) ?;
539+ write ! (
540+ file,
541+ "{}: {}" ,
542+ path. display( ) ,
543+ files
544+ . iter( )
545+ . map( |( path, _file_len, _checksum_hash_algo) | path. as_str( ) )
546+ . intersperse( " " )
547+ . collect:: <String >( )
548+ ) ?;
549+
550+ // If caller requested this information, add special comments about source file checksums.
551+ // These are not necessarily the same checksums as was used in the debug files.
552+ if sess. opts . unstable_opts . checksum_hash_algorithm ( ) . is_some ( ) {
553+ assert ! (
554+ files. iter( ) . all( |( _path, _file_len, hash_algo) | hash_algo. is_some( ) ) ,
555+ "all files must have a checksum hash computed to output checksum hashes"
556+ ) ;
557+ write ! ( file, " #" ) ?;
558+ files
559+ . iter ( )
560+ . filter_map ( |( _path, file_len, hash_algo) | {
561+ hash_algo. map ( |hash_algo| ( path, file_len, hash_algo) )
562+ } )
563+ . try_for_each ( |( _path, file_len, checksum_hash) | {
564+ write ! ( file, " checksum:{checksum_hash} file_len:{file_len}" )
565+ } ) ?;
566+ }
567+ write ! ( file, "\n \n " ) ?;
484568 }
485569
486570 // Emit a fake target for each input file to the compilation. This
487571 // prevents `make` from spitting out an error if a file is later
488572 // deleted. For more info see #28735
489- for path in files {
573+ for ( path, _file_len , _checksum_hash_algo ) in & files {
490574 writeln ! ( file, "{path}:" ) ?;
491575 }
492576
0 commit comments