@@ -375,6 +375,12 @@ pub fn generate_asts<'a>(
375
375
results
376
376
. into_iter ( )
377
377
. for_each ( |( module_name, ast_path, iast_path, deps, _namespace) | {
378
+ deps. iter ( ) . for_each ( |dep_name| {
379
+ if let Some ( module) = modules. get_mut ( dep_name) {
380
+ module. reverse_deps . insert ( module_name. to_string ( ) ) ;
381
+ }
382
+ } ) ;
383
+
378
384
if let Some ( module) = modules. get_mut ( & module_name) {
379
385
module. deps = deps;
380
386
match ast_path {
@@ -508,6 +514,7 @@ pub fn parse_packages(
508
514
Module {
509
515
source_type : SourceType :: MlMap ( MlMap { dirty : false } ) ,
510
516
deps : deps,
517
+ reverse_deps : AHashSet :: new ( ) ,
511
518
package : package. to_owned ( ) ,
512
519
compile_dirty : false ,
513
520
} ,
@@ -559,6 +566,7 @@ pub fn parse_packages(
559
566
interface : None ,
560
567
} ) ,
561
568
deps : AHashSet :: new ( ) ,
569
+ reverse_deps : AHashSet :: new ( ) ,
562
570
package : package. to_owned ( ) ,
563
571
compile_dirty : true ,
564
572
} ) ;
@@ -596,6 +604,7 @@ pub fn parse_packages(
596
604
} ) ,
597
605
} ) ,
598
606
deps : AHashSet :: new ( ) ,
607
+ reverse_deps : AHashSet :: new ( ) ,
599
608
package : package. to_owned ( ) ,
600
609
compile_dirty : true ,
601
610
} ) ;
@@ -868,6 +877,7 @@ pub fn build(path: &str) -> Result<AHashMap<std::string::String, Module>, ()> {
868
877
let timing_package_tree = Instant :: now ( ) ;
869
878
let packages = package_tree:: make ( & project_root) ;
870
879
let timing_package_tree_elapsed = timing_package_tree. elapsed ( ) ;
880
+
871
881
println ! (
872
882
"{}\r {} {}Built package tree in {:.2}s" ,
873
883
LINE_CLEAR ,
@@ -954,28 +964,15 @@ pub fn build(path: &str) -> Result<AHashMap<std::string::String, Module>, ()> {
954
964
}
955
965
}
956
966
957
- let pb = ProgressBar :: new ( modules. len ( ) . try_into ( ) . unwrap ( ) ) ;
958
- pb. set_style (
959
- ProgressStyle :: with_template ( & format ! (
960
- "{} {} Compiling... {{wide_bar}} {{pos}}/{{len}} {{msg}}" ,
961
- style( "[5/5]" ) . bold( ) . dim( ) ,
962
- SWORDS
963
- ) )
964
- . unwrap ( ) ,
965
- ) ;
966
967
let start_compiling = Instant :: now ( ) ;
967
968
968
969
let mut compiled_modules = AHashSet :: < String > :: new ( ) ;
969
- // println!("Clean modules:");
970
970
let dirty_modules = modules
971
971
. iter ( )
972
972
. filter_map ( |( module_name, module) | {
973
- // if is_dirty(module) {
974
973
if module. compile_dirty {
975
- // println!("> {}", module_name);
976
974
Some ( module_name. to_owned ( ) )
977
975
} else {
978
- // println!("> {}", module_name);
979
976
None
980
977
}
981
978
} )
@@ -993,108 +990,81 @@ pub fn build(path: &str) -> Result<AHashMap<std::string::String, Module>, ()> {
993
990
let mut files_current_loop_count;
994
991
let mut compile_errors = "" . to_string ( ) ;
995
992
let mut compile_warnings = "" . to_string ( ) ;
996
- let total_modules = modules. len ( ) ;
997
993
let mut num_compiled_modules = 0 ;
998
994
let mut sorted_modules = modules
999
995
. iter ( )
1000
996
. map ( |( module_name, _) | module_name. to_owned ( ) )
1001
997
. collect :: < Vec < String > > ( ) ;
1002
998
sorted_modules. sort ( ) ;
1003
999
1000
+ // for module in dirty_modules.clone() {
1001
+ // println!("dirty module: {}", module);
1002
+ // }
1003
+
1004
+ // this is the whole "compile universe" all modules that might be dirty
1005
+ // we get this by traversing from the dirty modules to all the modules that
1006
+ // are dependent on them
1007
+ let mut compile_universe = dirty_modules. clone ( ) ;
1008
+
1009
+ let mut current_step_modules = dirty_modules. clone ( ) ;
1004
1010
loop {
1005
- if dirty_modules. len ( ) == 0 {
1006
- break ;
1011
+ let mut reverse_deps: AHashSet < String > = AHashSet :: new ( ) ;
1012
+ for dirty_module in current_step_modules. iter ( ) {
1013
+ reverse_deps. extend ( modules. get ( dirty_module) . unwrap ( ) . reverse_deps . clone ( ) ) ;
1007
1014
}
1008
- let mut indirectly_dirty_modules = dirty_modules. clone ( ) ;
1009
- let mut checked_modules = AHashSet :: with_capacity ( modules. len ( ) ) ;
1010
- loop {
1011
- let mut num_checked_modules = 0 ;
1012
- for ( module_name, module) in modules. iter ( ) {
1013
- if !checked_modules. contains ( module_name) {
1014
- num_checked_modules += 1 ;
1015
- if module. deps . is_subset ( & checked_modules) {
1016
- checked_modules. insert ( module_name. to_string ( ) ) ;
1017
- let is_dirty = module. deps . iter ( ) . any ( |dep| {
1018
- if clean_modules. contains ( dep) {
1019
- return false ;
1020
- }
1021
- if indirectly_dirty_modules. contains ( dep) {
1022
- return true ;
1023
- }
1024
- return false ;
1025
- } ) ;
1026
- // if !module.deps.is_disjoint(&indirectly_dirty_modules) {
1027
- // indirectly_dirty_modules.insert(module_name.to_string());
1028
- // }
1029
- if is_dirty {
1030
- indirectly_dirty_modules. insert ( module_name. to_string ( ) ) ;
1031
- }
1032
- }
1033
- }
1034
- }
1035
- if num_checked_modules == 0 {
1036
- break ;
1037
- }
1015
+ current_step_modules = reverse_deps
1016
+ . difference ( & compile_universe)
1017
+ . map ( |s| s. to_string ( ) )
1018
+ . collect :: < AHashSet < String > > ( ) ;
1019
+ compile_universe. extend ( current_step_modules. clone ( ) ) ;
1020
+ if current_step_modules. is_empty ( ) {
1021
+ break ;
1038
1022
}
1039
- // let to_check_modules: Vec<(&String, &Module)> = modules
1040
- // .iter()
1041
- // .filter(|(module_name, _)| !checked_modules.contains(*module_name))
1042
- // .collect();
1043
- // to_check_modules.iter().for_each(|(module_name, _)| {
1044
- // let _ = checked_modules.insert(module_name.to_string());
1045
- // });
1046
- // Parallel version -- much faster in a debug build but slower in a release build...
1047
- // to_check_modules
1048
- // .par_iter()
1049
- // .map(|(module_name, module)| {
1050
- // if module.deps.is_subset(&checked_modules) {
1051
- // // checked_modules.insert(module_name.to_string());
1052
- // let is_dirty = module.deps.iter().any(|dep| {
1053
- // if clean_modules.contains(dep) {
1054
- // return false;
1055
- // }
1056
- // if indirectly_dirty_modules.contains(dep) {
1057
- // return true;
1058
- // }
1059
- // return false;
1060
- // });
1061
-
1062
- // if is_dirty {
1063
- // return Some(module_name);
1064
- // }
1065
- // }
1066
- // return None;
1067
- // })
1068
- // .filter_map(|x| x)
1069
- // .collect::<Vec<&&String>>()
1070
- // .iter()
1071
- // .for_each(|module_name| {
1072
- // indirectly_dirty_modules.insert(module_name.to_string());
1073
- // });
1074
- // if to_check_modules.len() == 0 {
1075
- // break;
1076
- // }
1023
+ }
1024
+ let pb = ProgressBar :: new ( compile_universe. len ( ) . try_into ( ) . unwrap ( ) ) ;
1025
+ pb. set_style (
1026
+ ProgressStyle :: with_template ( & format ! (
1027
+ "{} {} Compiling... {{wide_bar}} {{pos}}/{{len}} {{msg}}" ,
1028
+ style( "[5/5]" ) . bold( ) . dim( ) ,
1029
+ SWORDS
1030
+ ) )
1031
+ . unwrap ( ) ,
1032
+ ) ;
1077
1033
1034
+ // start off with all modules that have no deps in this compile universe
1035
+ let mut in_progress_modules = compile_universe
1036
+ . iter ( )
1037
+ . filter ( |module_name| {
1038
+ let module = modules. get ( * module_name) . unwrap ( ) ;
1039
+ module. deps . intersection ( & compile_universe) . count ( ) == 0
1040
+ } )
1041
+ . map ( |module_name| module_name. to_string ( ) )
1042
+ . collect :: < AHashSet < String > > ( ) ;
1043
+
1044
+ loop {
1078
1045
files_current_loop_count = 0 ;
1079
1046
loop_count += 1 ;
1080
1047
1081
1048
info ! (
1082
1049
"Compiled: {} out of {}. Compile loop: {}" ,
1083
1050
files_total_count,
1084
- modules . len( ) ,
1051
+ compile_universe . len( ) ,
1085
1052
loop_count,
1086
1053
) ;
1087
1054
1088
- sorted_modules
1089
- // .iter ()
1055
+ in_progress_modules
1056
+ . clone ( )
1090
1057
. par_iter ( )
1091
1058
. map ( |module_name| {
1092
1059
let module = modules. get ( module_name) . unwrap ( ) ;
1093
- if module. deps . is_subset ( & compiled_modules)
1094
- && !compiled_modules. contains ( module_name)
1060
+ // all dependencies that we care about are compiled
1061
+ if module
1062
+ . deps
1063
+ . intersection ( & compile_universe)
1064
+ . all ( |dep| compiled_modules. contains ( dep) )
1095
1065
{
1096
- if !indirectly_dirty_modules . contains ( module_name ) {
1097
- // we are sure we don't have to compile this, so we can mark it as compiled
1066
+ if !module . compile_dirty {
1067
+ // we are sure we don't have to compile this, so we can mark it as compiled and clean
1098
1068
return Some ( (
1099
1069
module_name. to_string ( ) ,
1100
1070
Ok ( None ) ,
@@ -1145,10 +1115,6 @@ pub fn build(path: &str) -> Result<AHashMap<std::string::String, Module>, ()> {
1145
1115
}
1146
1116
_ => None ,
1147
1117
} ;
1148
- // if let Some(Err(error)) = interface_result.to_owned() {
1149
- // println!("{}", error);
1150
- // panic!("Interface compilation error!");
1151
- // }
1152
1118
let result = compile_file (
1153
1119
& module. package . name ,
1154
1120
& helpers:: get_ast_path (
@@ -1168,19 +1134,7 @@ pub fn build(path: &str) -> Result<AHashMap<std::string::String, Module>, ()> {
1168
1134
1169
1135
let is_clean = match ( cmi_digest, cmi_digest_after) {
1170
1136
( Some ( cmi_digest) , Some ( cmi_digest_after) ) => {
1171
- if cmi_digest. eq ( & cmi_digest_after) {
1172
- // println!(
1173
- // "{} is clean -- {:x} {:x}",
1174
- // cmi_path, cmi_digest, cmi_digest_after
1175
- // );
1176
- true
1177
- } else {
1178
- // println!(
1179
- // "{} is dirty -- {:x} {:x}",
1180
- // cmi_path, cmi_digest, cmi_digest_after
1181
- // );
1182
- false
1183
- }
1137
+ cmi_digest. eq ( & cmi_digest_after)
1184
1138
}
1185
1139
1186
1140
_ => false ,
@@ -1210,12 +1164,15 @@ pub fn build(path: &str) -> Result<AHashMap<std::string::String, Module>, ()> {
1210
1164
. iter ( )
1211
1165
. for_each ( |result| match result {
1212
1166
Some ( ( module_name, result, interface_result, is_clean, is_compiled) ) => {
1167
+ in_progress_modules. remove ( module_name) ;
1168
+
1213
1169
if !( log_enabled ! ( Info ) ) {
1214
1170
pb. inc ( 1 ) ;
1215
1171
}
1216
1172
if * is_compiled {
1217
1173
num_compiled_modules += 1 ;
1218
1174
}
1175
+
1219
1176
files_current_loop_count += 1 ;
1220
1177
compiled_modules. insert ( module_name. to_string ( ) ) ;
1221
1178
@@ -1224,6 +1181,21 @@ pub fn build(path: &str) -> Result<AHashMap<std::string::String, Module>, ()> {
1224
1181
clean_modules. insert ( module_name. to_string ( ) ) ;
1225
1182
}
1226
1183
1184
+ let module_reverse_deps =
1185
+ modules. get ( module_name) . unwrap ( ) . reverse_deps . clone ( ) ;
1186
+
1187
+ // if not clean -- compile modules that depend on this module
1188
+ for dep in module_reverse_deps. iter ( ) {
1189
+ let dep_module = modules. get_mut ( dep) . unwrap ( ) ;
1190
+ // mark the reverse dep as dirty when the source is not clean
1191
+ if !* is_clean {
1192
+ dep_module. compile_dirty = true ;
1193
+ }
1194
+ if !compiled_modules. contains ( dep) {
1195
+ in_progress_modules. insert ( dep. to_string ( ) ) ;
1196
+ }
1197
+ }
1198
+
1227
1199
let module = modules. get_mut ( module_name) . unwrap ( ) ;
1228
1200
1229
1201
match module. source_type {
@@ -1263,13 +1235,16 @@ pub fn build(path: &str) -> Result<AHashMap<std::string::String, Module>, ()> {
1263
1235
1264
1236
files_total_count += files_current_loop_count;
1265
1237
1266
- if files_total_count == total_modules {
1238
+ // if files_total_count == total_modules {
1239
+ // break;
1240
+ // }
1241
+ // if files_current_loop_count == 0 {
1242
+ // // we probably want to find the cycle(s), and give a helpful error message here
1243
+ // compile_errors.push_str("Can't continue... Dependency cycle\n")
1244
+ // }
1245
+ if in_progress_modules. len ( ) == 0 {
1267
1246
break ;
1268
1247
}
1269
- if files_current_loop_count == 0 {
1270
- // we probably want to find the cycle(s), and give a helpful error message here
1271
- compile_errors. push_str ( "Can't continue... Dependency cycle\n " )
1272
- }
1273
1248
if compile_errors. len ( ) > 0 {
1274
1249
break ;
1275
1250
} ;
@@ -1279,6 +1254,10 @@ pub fn build(path: &str) -> Result<AHashMap<std::string::String, Module>, ()> {
1279
1254
pb. finish ( ) ;
1280
1255
clean:: cleanup_after_build ( & modules, & compiled_modules, & all_modules, & project_root) ;
1281
1256
if compile_errors. len ( ) > 0 {
1257
+ if helpers:: contains_ascii_characters ( & compile_warnings) {
1258
+ println ! ( "{}" , & compile_warnings) ;
1259
+ }
1260
+ println ! ( "{}" , & compile_errors) ;
1282
1261
println ! (
1283
1262
"{}\r {} {}Compiled {} modules in {:.2}s" ,
1284
1263
LINE_CLEAR ,
@@ -1287,12 +1266,11 @@ pub fn build(path: &str) -> Result<AHashMap<std::string::String, Module>, ()> {
1287
1266
num_compiled_modules,
1288
1267
compile_duration. as_secs_f64( )
1289
1268
) ;
1269
+ return Err ( ( ) ) ;
1270
+ } else {
1290
1271
if helpers:: contains_ascii_characters ( & compile_warnings) {
1291
1272
println ! ( "{}" , & compile_warnings) ;
1292
1273
}
1293
- println ! ( "{}" , & compile_errors) ;
1294
- return Err ( ( ) ) ;
1295
- } else {
1296
1274
println ! (
1297
1275
"{}\r {} {}Compiled {} modules in {:.2}s" ,
1298
1276
LINE_CLEAR ,
@@ -1301,9 +1279,6 @@ pub fn build(path: &str) -> Result<AHashMap<std::string::String, Module>, ()> {
1301
1279
num_compiled_modules,
1302
1280
compile_duration. as_secs_f64( )
1303
1281
) ;
1304
- if helpers:: contains_ascii_characters ( & compile_warnings) {
1305
- println ! ( "{}" , & compile_warnings) ;
1306
- }
1307
1282
}
1308
1283
1309
1284
let timing_total_elapsed = timing_total. elapsed ( ) ;
0 commit comments