@@ -271,6 +271,35 @@ impl VerusTarget {
271271 if !ts. exists ( ) {
272272 return false ;
273273 }
274+
275+ // Check if our own verification file exists
276+ if !self . library_proof ( ) . exists ( ) {
277+ return false ;
278+ }
279+
280+ // Get our own timestamp
281+ let self_timestamp = match std:: fs:: metadata ( & self . library_proof ( ) ) {
282+ Ok ( metadata) => metadata. modified ( ) . unwrap_or ( std:: time:: UNIX_EPOCH ) ,
283+ Err ( _) => return false ,
284+ } ;
285+
286+ // Check if all recursive dependencies have their verification files and are not newer than us
287+ let deps = get_local_dependency_recursive ( self ) ;
288+ for dep in deps. values ( ) {
289+ if !dep. library_proof ( ) . exists ( ) {
290+ return false ;
291+ }
292+
293+ // Check if dependency is newer than us
294+ if let Ok ( dep_metadata) = std:: fs:: metadata ( & dep. library_proof ( ) ) {
295+ if let Ok ( dep_timestamp) = dep_metadata. modified ( ) {
296+ if dep_timestamp > self_timestamp {
297+ return false ; // Dependency is newer, we need to rebuild
298+ }
299+ }
300+ }
301+ }
302+
274303 let ts_hash = self . load_library_proof_timestamp ( ) ;
275304 let cur_hash = self . fingerprint_recursive ( all_targets) ;
276305 if cur_hash == ts_hash {
@@ -537,8 +566,44 @@ pub fn get_local_dependency(target: &VerusTarget) -> IndexMap<String, VerusTarge
537566 deps
538567}
539568
569+ pub fn get_local_dependency_recursive ( target : & VerusTarget ) -> IndexMap < String , VerusTarget > {
570+ let mut result = IndexMap :: new ( ) ;
571+ let mut visited = std:: collections:: HashSet :: new ( ) ;
572+
573+ fn collect_deps_recursive (
574+ target : & VerusTarget ,
575+ result : & mut IndexMap < String , VerusTarget > ,
576+ visited : & mut std:: collections:: HashSet < String > ,
577+ _is_root : bool ,
578+ ) {
579+ let target_name = target. name . replace ( '-' , "_" ) ;
580+
581+ // Prevent infinite recursion
582+ if visited. contains ( & target_name) {
583+ return ;
584+ }
585+ visited. insert ( target_name. clone ( ) ) ;
586+
587+ // Get direct dependencies
588+ let direct_deps = get_local_dependency ( target) ;
589+
590+ // Add direct dependencies to result (unless it's the root target)
591+ for ( dep_name, dep_target) in direct_deps. iter ( ) {
592+ let dep_key = dep_name. replace ( '-' , "_" ) ;
593+ if !result. contains_key ( & dep_key) {
594+ result. insert ( dep_key, dep_target. clone ( ) ) ;
595+ }
596+ // Recursively collect dependencies of this dependency
597+ collect_deps_recursive ( dep_target, result, visited, false ) ;
598+ }
599+ }
600+
601+ collect_deps_recursive ( target, & mut result, & mut visited, true ) ;
602+ result
603+ }
604+
540605pub fn get_dependent_targets ( target : & VerusTarget , release : bool ) -> IndexMap < String , VerusTarget > {
541- let mut deps = get_local_dependency ( target) ;
606+ let mut deps = get_local_dependency_recursive ( target) ;
542607 let order = resolve_deps_cached ( target, release) . full_externs ;
543608 deps. sort_by ( |a, _, b, _| {
544609 let x = order. get_index_of ( a) . unwrap_or ( usize:: MAX ) ;
@@ -554,7 +619,7 @@ pub fn get_dependent_targets_batch(
554619) -> IndexMap < String , VerusTarget > {
555620 let mut deps = IndexMap :: new ( ) ;
556621 for target in targets. iter ( ) {
557- deps. extend ( get_local_dependency ( target) ) ;
622+ deps. extend ( get_local_dependency_recursive ( target) ) ;
558623 }
559624 let order = resolve_deps_cached ( targets. first ( ) . unwrap ( ) , release) . full_externs ;
560625 deps. sort_by ( |a, _, b, _| {
@@ -622,6 +687,49 @@ pub fn check_import(imports: &[&VerusTarget]) -> Result<(), DynError> {
622687 Ok ( ( ) )
623688}
624689
690+ pub fn check_import_with_auto_compile (
691+ imports : & [ & VerusTarget ] ,
692+ options : & ExtraOptions ,
693+ ) -> Result < ( ) , DynError > {
694+ let mut missing_targets = Vec :: new ( ) ;
695+
696+ for imp in imports. iter ( ) {
697+ if !imp. library_proof ( ) . exists ( ) || !imp. library_path ( ) . exists ( ) {
698+ missing_targets. push ( ( * imp) . clone ( ) ) ;
699+ }
700+ }
701+
702+ if !missing_targets. is_empty ( ) {
703+ info ! (
704+ "Missing verification files for dependencies: {:?}" ,
705+ missing_targets. iter( ) . map( |t| & t. name) . collect:: <Vec <_>>( )
706+ ) ;
707+ info ! ( "Automatically compiling missing dependencies..." ) ;
708+
709+ // Get all dependencies of missing targets to ensure proper compilation order
710+ let extended_targets = get_dependent_targets_batch ( & missing_targets, options. release ) ;
711+ for target in extended_targets. values ( ) {
712+ if !target. library_proof ( ) . exists ( ) {
713+ compile_target ( target, & vec ! [ ] , options) . map_err ( |e| {
714+ format ! ( "Failed to auto-compile dependency `{}`: {}" , target. name, e)
715+ } ) ?;
716+ }
717+ }
718+
719+ // Compile the missing targets themselves
720+ for target in & missing_targets {
721+ if !target. library_proof ( ) . exists ( ) {
722+ compile_target ( target, & vec ! [ ] , options) . map_err ( |e| {
723+ format ! ( "Failed to auto-compile dependency `{}`: {}" , target. name, e)
724+ } ) ?;
725+ }
726+ }
727+ }
728+
729+ // Final check
730+ check_import ( imports)
731+ }
732+
625733pub fn check_externs ( externs : & IndexMap < String , String > ) -> Result < ( ) , DynError > {
626734 for ( name, path) in externs. iter ( ) {
627735 if !Path :: new ( path) . exists ( ) {
@@ -757,7 +865,7 @@ pub fn compile_target(
757865
758866 prepare ( target, options. release ) ;
759867
760- let mut deps = get_local_dependency ( target) ;
868+ let mut deps = get_local_dependency_recursive ( target) ;
761869 let dep_rebuilt = deps. values ( ) . into_iter ( ) . any ( |t| t. rebuilt == true ) ;
762870
763871 if !dep_rebuilt && target. is_fresh ( & verus_targets ( ) ) {
@@ -791,7 +899,7 @@ pub fn compile_target(
791899 // imported dependencies
792900 deps. extend ( extra_imports. clone ( ) ) ;
793901 let all_imports = deps. values ( ) . collect :: < Vec < _ > > ( ) ;
794- check_import ( all_imports. as_slice ( ) ) . unwrap_or_else ( |e| {
902+ check_import_with_auto_compile ( all_imports. as_slice ( ) , options ) . unwrap_or_else ( |e| {
795903 error ! ( "Error during verification: {}" , e) ;
796904 } ) ;
797905 cmd_push_import ( cmd, all_imports. as_slice ( ) ) ;
@@ -935,11 +1043,11 @@ pub fn exec_verify(
9351043 }
9361044
9371045 // imported dependencies
938- let deps = & mut get_local_dependency ( target) ;
1046+ let deps = & mut get_local_dependency_recursive ( target) ;
9391047 deps. extend ( extra_imports. clone ( ) ) ;
9401048 let all_imports = deps. values ( ) . collect :: < Vec < _ > > ( ) ;
9411049
942- check_import ( all_imports. as_slice ( ) ) . unwrap_or_else ( |e| {
1050+ check_import_with_auto_compile ( all_imports. as_slice ( ) , options ) . unwrap_or_else ( |e| {
9431051 error ! ( "Error during verification: {}" , e) ;
9441052 } ) ;
9451053 cmd_push_import ( cmd, all_imports. as_slice ( ) ) ;
@@ -1088,6 +1196,67 @@ pub fn exec_compile(
10881196 Ok ( ( ) )
10891197}
10901198
1199+ /// Clean build artefacts produced by `exec_compile`.
1200+ pub fn exec_clean ( targets : & [ VerusTarget ] , all : bool ) -> Result < ( ) , DynError > {
1201+ let out_dir = get_target_dir ( ) ;
1202+
1203+ let to_clean: Vec < VerusTarget > = if all || targets. is_empty ( ) {
1204+ // clean all known targets
1205+ verus_targets ( ) . values ( ) . cloned ( ) . collect ( )
1206+ } else {
1207+ targets. iter ( ) . cloned ( ) . collect ( )
1208+ } ;
1209+
1210+ for target in to_clean. iter ( ) {
1211+ // remove .verusdata
1212+ let proof = target. library_proof ( ) ;
1213+ if proof. exists ( ) {
1214+ info ! ( "Removing {}" , proof. display( ) ) ;
1215+ std:: fs:: remove_file ( & proof) . unwrap_or_else ( |e| {
1216+ warn ! ( "Failed to remove {}: {}" , proof. display( ) , e) ;
1217+ } ) ;
1218+ }
1219+
1220+ // remove .verusdata.timestamp
1221+ let proof_ts = target. library_proof_timestamp ( ) ;
1222+ if proof_ts. exists ( ) {
1223+ info ! ( "Removing {}" , proof_ts. display( ) ) ;
1224+ std:: fs:: remove_file ( & proof_ts) . unwrap_or_else ( |e| {
1225+ warn ! ( "Failed to remove {}: {}" , proof_ts. display( ) , e) ;
1226+ } ) ;
1227+ }
1228+
1229+ // remove lib{name}.rlib
1230+ let lib = target. library_path ( ) ;
1231+ if lib. exists ( ) {
1232+ info ! ( "Removing {}" , lib. display( ) ) ;
1233+ std:: fs:: remove_file ( & lib) . unwrap_or_else ( |e| {
1234+ warn ! ( "Failed to remove {}: {}" , lib. display( ) , e) ;
1235+ } ) ;
1236+ }
1237+
1238+ // remove generated extern_crates
1239+ let extern_crates_path = out_dir. join ( format ! ( "{}.extern_crates.rs" , target. name) ) ;
1240+ if extern_crates_path. exists ( ) {
1241+ info ! ( "Removing {}" , extern_crates_path. display( ) ) ;
1242+ std:: fs:: remove_file ( & extern_crates_path) . unwrap_or_else ( |e| {
1243+ warn ! ( "Failed to remove {}: {}" , extern_crates_path. display( ) , e) ;
1244+ } ) ;
1245+ }
1246+
1247+ // remove deps.toml
1248+ let deps_toml_path = out_dir. join ( format ! ( "{}.deps.toml" , target. name) ) ;
1249+ if deps_toml_path. exists ( ) {
1250+ info ! ( "Removing {}" , deps_toml_path. display( ) ) ;
1251+ std:: fs:: remove_file ( & deps_toml_path) . unwrap_or_else ( |e| {
1252+ warn ! ( "Failed to remove {}: {}" , deps_toml_path. display( ) , e) ;
1253+ } ) ;
1254+ }
1255+ }
1256+
1257+ Ok ( ( ) )
1258+ }
1259+
10911260pub mod install {
10921261 use super :: * ;
10931262 use crate :: toolchain;
0 commit comments