26
26
//! along with the actual implementation elsewhere. You can find more comments
27
27
//! about how to define rules themselves below.
28
28
29
- use std:: collections:: { BTreeMap , HashSet } ;
29
+ use std:: collections:: { BTreeMap , HashSet , HashMap } ;
30
30
use std:: mem;
31
31
32
32
use check:: { self , TestKind } ;
@@ -533,34 +533,44 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
533
533
//
534
534
// Tools used during the build system but not shipped
535
535
rules. build ( "tool-rustbook" , "src/tools/rustbook" )
536
- . dep ( |s| s. name ( "librustc" ) )
536
+ . dep ( |s| s. name ( "maybe-clean-tools" ) )
537
+ . dep ( |s| s. name ( "librustc-tool" ) )
537
538
. run ( move |s| compile:: tool ( build, s. stage , s. target , "rustbook" ) ) ;
538
539
rules. build ( "tool-error-index" , "src/tools/error_index_generator" )
539
- . dep ( |s| s. name ( "librustc" ) )
540
+ . dep ( |s| s. name ( "maybe-clean-tools" ) )
541
+ . dep ( |s| s. name ( "librustc-tool" ) )
540
542
. run ( move |s| compile:: tool ( build, s. stage , s. target , "error_index_generator" ) ) ;
541
543
rules. build ( "tool-tidy" , "src/tools/tidy" )
542
- . dep ( |s| s. name ( "libstd" ) )
544
+ . dep ( |s| s. name ( "maybe-clean-tools" ) )
545
+ . dep ( |s| s. name ( "libstd-tool" ) )
543
546
. run ( move |s| compile:: tool ( build, s. stage , s. target , "tidy" ) ) ;
544
547
rules. build ( "tool-linkchecker" , "src/tools/linkchecker" )
545
- . dep ( |s| s. name ( "libstd" ) )
548
+ . dep ( |s| s. name ( "maybe-clean-tools" ) )
549
+ . dep ( |s| s. name ( "libstd-tool" ) )
546
550
. run ( move |s| compile:: tool ( build, s. stage , s. target , "linkchecker" ) ) ;
547
551
rules. build ( "tool-cargotest" , "src/tools/cargotest" )
548
- . dep ( |s| s. name ( "libstd" ) )
552
+ . dep ( |s| s. name ( "maybe-clean-tools" ) )
553
+ . dep ( |s| s. name ( "libstd-tool" ) )
549
554
. run ( move |s| compile:: tool ( build, s. stage , s. target , "cargotest" ) ) ;
550
555
rules. build ( "tool-compiletest" , "src/tools/compiletest" )
551
- . dep ( |s| s. name ( "libtest" ) )
556
+ . dep ( |s| s. name ( "maybe-clean-tools" ) )
557
+ . dep ( |s| s. name ( "libtest-tool" ) )
552
558
. run ( move |s| compile:: tool ( build, s. stage , s. target , "compiletest" ) ) ;
553
559
rules. build ( "tool-build-manifest" , "src/tools/build-manifest" )
554
- . dep ( |s| s. name ( "libstd" ) )
560
+ . dep ( |s| s. name ( "maybe-clean-tools" ) )
561
+ . dep ( |s| s. name ( "libstd-tool" ) )
555
562
. run ( move |s| compile:: tool ( build, s. stage , s. target , "build-manifest" ) ) ;
556
563
rules. build ( "tool-qemu-test-server" , "src/tools/qemu-test-server" )
557
- . dep ( |s| s. name ( "libstd" ) )
564
+ . dep ( |s| s. name ( "maybe-clean-tools" ) )
565
+ . dep ( |s| s. name ( "libstd-tool" ) )
558
566
. run ( move |s| compile:: tool ( build, s. stage , s. target , "qemu-test-server" ) ) ;
559
567
rules. build ( "tool-qemu-test-client" , "src/tools/qemu-test-client" )
560
- . dep ( |s| s. name ( "libstd" ) )
568
+ . dep ( |s| s. name ( "maybe-clean-tools" ) )
569
+ . dep ( |s| s. name ( "libstd-tool" ) )
561
570
. run ( move |s| compile:: tool ( build, s. stage , s. target , "qemu-test-client" ) ) ;
562
571
rules. build ( "tool-cargo" , "cargo" )
563
- . dep ( |s| s. name ( "libstd" ) )
572
+ . dep ( |s| s. name ( "maybe-clean-tools" ) )
573
+ . dep ( |s| s. name ( "libstd-tool" ) )
564
574
. dep ( |s| s. stage ( 0 ) . host ( s. target ) . name ( "openssl" ) )
565
575
. dep ( move |s| {
566
576
// Cargo depends on procedural macros, which requires a full host
@@ -572,7 +582,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
572
582
. run ( move |s| compile:: tool ( build, s. stage , s. target , "cargo" ) ) ;
573
583
rules. build ( "tool-rls" , "rls" )
574
584
. host ( true )
575
- . dep ( |s| s. name ( "librustc" ) )
585
+ . dep ( |s| s. name ( "librustc-tool" ) )
586
+ . dep ( |s| s. stage ( 0 ) . host ( s. target ) . name ( "openssl" ) )
576
587
. dep ( move |s| {
577
588
// rls, like cargo, uses procedural macros
578
589
s. name ( "librustc-link" )
@@ -581,6 +592,25 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
581
592
} )
582
593
. run ( move |s| compile:: tool ( build, s. stage , s. target , "rls" ) ) ;
583
594
595
+ // "pseudo rule" which represents completely cleaning out the tools dir in
596
+ // one stage. This needs to happen whenever a dependency changes (e.g.
597
+ // libstd, libtest, librustc) and all of the tool compilations above will
598
+ // be sequenced after this rule.
599
+ rules. build ( "maybe-clean-tools" , "path/to/nowhere" )
600
+ . after ( "librustc-tool" )
601
+ . after ( "libtest-tool" )
602
+ . after ( "libstd-tool" ) ;
603
+
604
+ rules. build ( "librustc-tool" , "path/to/nowhere" )
605
+ . dep ( |s| s. name ( "librustc" ) )
606
+ . run ( move |s| compile:: maybe_clean_tools ( build, s. stage , s. target , Mode :: Librustc ) ) ;
607
+ rules. build ( "libtest-tool" , "path/to/nowhere" )
608
+ . dep ( |s| s. name ( "libtest" ) )
609
+ . run ( move |s| compile:: maybe_clean_tools ( build, s. stage , s. target , Mode :: Libtest ) ) ;
610
+ rules. build ( "libstd-tool" , "path/to/nowhere" )
611
+ . dep ( |s| s. name ( "libstd" ) )
612
+ . run ( move |s| compile:: maybe_clean_tools ( build, s. stage , s. target , Mode :: Libstd ) ) ;
613
+
584
614
// ========================================================================
585
615
// Documentation targets
586
616
rules. doc ( "doc-book" , "src/doc/book" )
@@ -828,6 +858,11 @@ struct Rule<'a> {
828
858
/// Whether this rule is only for the build triple, not anything in hosts or
829
859
/// targets.
830
860
only_build : bool ,
861
+
862
+ /// A list of "order only" dependencies. This rules does not actually
863
+ /// depend on these rules, but if they show up in the dependency graph then
864
+ /// this rule must be executed after all these rules.
865
+ after : Vec < & ' a str > ,
831
866
}
832
867
833
868
#[ derive( PartialEq ) ]
@@ -851,6 +886,7 @@ impl<'a> Rule<'a> {
851
886
host : false ,
852
887
only_host_build : false ,
853
888
only_build : false ,
889
+ after : Vec :: new ( ) ,
854
890
}
855
891
}
856
892
}
@@ -870,6 +906,11 @@ impl<'a, 'b> RuleBuilder<'a, 'b> {
870
906
self
871
907
}
872
908
909
+ fn after ( & mut self , step : & ' a str ) -> & mut Self {
910
+ self . rule . after . push ( step) ;
911
+ self
912
+ }
913
+
873
914
fn run < F > ( & mut self , f : F ) -> & mut Self
874
915
where F : Fn ( & Step < ' a > ) + ' a ,
875
916
{
@@ -1153,31 +1194,52 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
1153
1194
/// From the top level targets `steps` generate a topological ordering of
1154
1195
/// all steps needed to run those steps.
1155
1196
fn expand ( & self , steps : & [ Step < ' a > ] ) -> Vec < Step < ' a > > {
1197
+ // First up build a graph of steps and their dependencies. The `nodes`
1198
+ // map is a map from step to a unique number. The `edges` map is a
1199
+ // map from these unique numbers to a list of other numbers,
1200
+ // representing dependencies.
1201
+ let mut nodes = HashMap :: new ( ) ;
1202
+ nodes. insert ( Step :: noop ( ) , 0 ) ;
1203
+ let mut edges = HashMap :: new ( ) ;
1204
+ edges. insert ( 0 , HashSet :: new ( ) ) ;
1205
+ for step in steps {
1206
+ self . build_graph ( step. clone ( ) , & mut nodes, & mut edges) ;
1207
+ }
1208
+
1209
+ // Now that we've built up the actual dependency graph, draw more
1210
+ // dependency edges to satisfy the `after` dependencies field for each
1211
+ // rule.
1212
+ self . satisfy_after_deps ( & nodes, & mut edges) ;
1213
+
1214
+ // And finally, perform a topological sort to return a list of steps to
1215
+ // execute.
1156
1216
let mut order = Vec :: new ( ) ;
1157
- let mut added = HashSet :: new ( ) ;
1158
- added. insert ( Step :: noop ( ) ) ;
1159
- for step in steps. iter ( ) . cloned ( ) {
1160
- self . fill ( step, & mut order, & mut added) ;
1217
+ let mut visited = HashSet :: new ( ) ;
1218
+ visited. insert ( 0 ) ;
1219
+ let idx_to_node = nodes. iter ( ) . map ( |p| ( * p. 1 , p. 0 ) ) . collect :: < HashMap < _ , _ > > ( ) ;
1220
+ for idx in nodes. values ( ) {
1221
+ self . topo_sort ( * idx, & idx_to_node, & edges, & mut visited, & mut order) ;
1161
1222
}
1162
1223
return order
1163
1224
}
1164
1225
1165
- /// Performs topological sort of dependencies rooted at the `step`
1166
- /// specified, pushing all results onto the `order` vector provided.
1226
+ /// Builds the dependency graph rooted at `step`.
1167
1227
///
1168
- /// In other words, when this method returns, the `order` vector will
1169
- /// contain a list of steps which if executed in order will eventually
1170
- /// complete the `step` specified as well.
1171
- ///
1172
- /// The `added` set specified here is the set of steps that are already
1173
- /// present in `order` (and hence don't need to be added again).
1174
- fn fill ( & self ,
1175
- step : Step < ' a > ,
1176
- order : & mut Vec < Step < ' a > > ,
1177
- added : & mut HashSet < Step < ' a > > ) {
1178
- if !added . insert ( step . clone ( ) ) {
1179
- return
1228
+ /// The `nodes` and `edges` maps are filled out according to the rule
1229
+ /// described by `step.name`.
1230
+ fn build_graph ( & self ,
1231
+ step : Step < ' a > ,
1232
+ nodes : & mut HashMap < Step < ' a > , usize > ,
1233
+ edges : & mut HashMap < usize , HashSet < usize > > ) -> usize {
1234
+ use std :: collections :: hash_map :: Entry ;
1235
+
1236
+ let idx = nodes . len ( ) ;
1237
+ match nodes . entry ( step . clone ( ) ) {
1238
+ Entry :: Vacant ( e ) => { e . insert ( idx ) ; }
1239
+ Entry :: Occupied ( e ) => return * e . get ( ) ,
1180
1240
}
1241
+
1242
+ let mut deps = Vec :: new ( ) ;
1181
1243
for dep in self . rules [ step. name ] . deps . iter ( ) {
1182
1244
let dep = dep ( & step) ;
1183
1245
if dep. name . starts_with ( "default:" ) {
@@ -1189,13 +1251,61 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
1189
1251
let host = self . build . config . host . iter ( ) . any ( |h| h == dep. target ) ;
1190
1252
let rules = self . rules . values ( ) . filter ( |r| r. default ) ;
1191
1253
for rule in rules. filter ( |r| r. kind == kind && ( !r. host || host) ) {
1192
- self . fill ( dep. name ( rule. name ) , order , added ) ;
1254
+ deps . push ( self . build_graph ( dep. name ( rule. name ) , nodes , edges ) ) ;
1193
1255
}
1194
1256
} else {
1195
- self . fill ( dep, order, added) ;
1257
+ deps. push ( self . build_graph ( dep, nodes, edges) ) ;
1258
+ }
1259
+ }
1260
+
1261
+ edges. entry ( idx) . or_insert ( HashSet :: new ( ) ) . extend ( deps) ;
1262
+ return idx
1263
+ }
1264
+
1265
+ /// Given a dependency graph with a finished list of `nodes`, fill out more
1266
+ /// dependency `edges`.
1267
+ ///
1268
+ /// This is the step which satisfies all `after` listed dependencies in
1269
+ /// `Rule` above.
1270
+ fn satisfy_after_deps ( & self ,
1271
+ nodes : & HashMap < Step < ' a > , usize > ,
1272
+ edges : & mut HashMap < usize , HashSet < usize > > ) {
1273
+ // Reverse map from the name of a step to the node indices that it
1274
+ // appears at.
1275
+ let mut name_to_idx = HashMap :: new ( ) ;
1276
+ for ( step, & idx) in nodes {
1277
+ name_to_idx. entry ( step. name ) . or_insert ( Vec :: new ( ) ) . push ( idx) ;
1278
+ }
1279
+
1280
+ for ( step, idx) in nodes {
1281
+ if * step == Step :: noop ( ) {
1282
+ continue
1283
+ }
1284
+ for after in self . rules [ step. name ] . after . iter ( ) {
1285
+ // This is the critical piece of an `after` dependency. If the
1286
+ // dependency isn't actually in our graph then no edge is drawn,
1287
+ // only if it's already present do we draw the edges.
1288
+ if let Some ( idxs) = name_to_idx. get ( after) {
1289
+ edges. get_mut ( idx) . unwrap ( )
1290
+ . extend ( idxs. iter ( ) . cloned ( ) ) ;
1291
+ }
1196
1292
}
1197
1293
}
1198
- order. push ( step) ;
1294
+ }
1295
+
1296
+ fn topo_sort ( & self ,
1297
+ cur : usize ,
1298
+ nodes : & HashMap < usize , & Step < ' a > > ,
1299
+ edges : & HashMap < usize , HashSet < usize > > ,
1300
+ visited : & mut HashSet < usize > ,
1301
+ order : & mut Vec < Step < ' a > > ) {
1302
+ if !visited. insert ( cur) {
1303
+ return
1304
+ }
1305
+ for dep in edges[ & cur] . iter ( ) {
1306
+ self . topo_sort ( * dep, nodes, edges, visited, order) ;
1307
+ }
1308
+ order. push ( nodes[ & cur] . clone ( ) ) ;
1199
1309
}
1200
1310
}
1201
1311
0 commit comments