15
15
//! (for example, with and without tests), so we actually build a dependency
16
16
//! graph of `Unit`s, which capture these properties.
17
17
18
- use std:: cell:: RefCell ;
19
- use std:: collections:: { HashMap , HashSet } ;
20
-
21
- use log:: trace;
22
-
23
- use super :: { BuildContext , CompileMode , Kind } ;
24
18
use crate :: core:: compiler:: Unit ;
19
+ use crate :: core:: compiler:: { BuildContext , CompileMode , Context , Kind } ;
25
20
use crate :: core:: dependency:: Kind as DepKind ;
26
21
use crate :: core:: package:: Downloads ;
27
22
use crate :: core:: profiles:: UnitFor ;
28
23
use crate :: core:: { Package , PackageId , Target } ;
29
24
use crate :: CargoResult ;
25
+ use log:: trace;
26
+ use std:: collections:: { HashMap , HashSet } ;
30
27
31
28
struct State < ' a : ' tmp , ' cfg : ' a , ' tmp > {
32
- bcx : & ' tmp BuildContext < ' a , ' cfg > ,
33
- deps : & ' tmp mut HashMap < Unit < ' a > , Vec < Unit < ' a > > > ,
34
- pkgs : RefCell < & ' tmp mut HashMap < PackageId , & ' a Package > > ,
29
+ cx : & ' tmp mut Context < ' a , ' cfg > ,
35
30
waiting_on_download : HashSet < PackageId > ,
36
31
downloads : Downloads < ' a , ' cfg > ,
37
32
}
38
33
39
34
pub fn build_unit_dependencies < ' a , ' cfg > (
35
+ cx : & mut Context < ' a , ' cfg > ,
40
36
roots : & [ Unit < ' a > ] ,
41
- bcx : & BuildContext < ' a , ' cfg > ,
42
- deps : & mut HashMap < Unit < ' a > , Vec < Unit < ' a > > > ,
43
- pkgs : & mut HashMap < PackageId , & ' a Package > ,
44
37
) -> CargoResult < ( ) > {
45
- assert ! ( deps. is_empty( ) , "can only build unit deps once" ) ;
38
+ assert ! (
39
+ cx. unit_dependencies. is_empty( ) ,
40
+ "can only build unit deps once"
41
+ ) ;
46
42
47
43
let mut state = State {
48
- bcx,
49
- deps,
50
- pkgs : RefCell :: new ( pkgs) ,
44
+ downloads : cx. bcx . packages . enable_download ( ) ?,
45
+ cx,
51
46
waiting_on_download : HashSet :: new ( ) ,
52
- downloads : bcx. packages . enable_download ( ) ?,
53
47
} ;
54
48
55
49
loop {
@@ -62,7 +56,7 @@ pub fn build_unit_dependencies<'a, 'cfg>(
62
56
// cleared, and avoid building the lib thrice (once with `panic`, once
63
57
// without, once for `--test`). In particular, the lib included for
64
58
// Doc tests and examples are `Build` mode here.
65
- let unit_for = if unit. mode . is_any_test ( ) || bcx. build_config . test ( ) {
59
+ let unit_for = if unit. mode . is_any_test ( ) || state . cx . bcx . build_config . test ( ) {
66
60
UnitFor :: new_test ( )
67
61
} else if unit. target . is_custom_build ( ) {
68
62
// This normally doesn't happen, except `clean` aggressively
@@ -79,20 +73,23 @@ pub fn build_unit_dependencies<'a, 'cfg>(
79
73
80
74
if !state. waiting_on_download . is_empty ( ) {
81
75
state. finish_some_downloads ( ) ?;
82
- state. deps . clear ( ) ;
76
+ state. cx . unit_dependencies . clear ( ) ;
83
77
} else {
84
78
break ;
85
79
}
86
80
}
87
- trace ! ( "ALL UNIT DEPENDENCIES {:#?}" , state. deps) ;
88
81
89
82
connect_run_custom_build_deps ( & mut state) ;
90
83
84
+ trace ! ( "ALL UNIT DEPENDENCIES {:#?}" , state. cx. unit_dependencies) ;
85
+
86
+ record_units_requiring_metadata ( state. cx ) ;
87
+
91
88
// Dependencies are used in tons of places throughout the backend, many of
92
89
// which affect the determinism of the build itself. As a result be sure
93
90
// that dependency lists are always sorted to ensure we've always got a
94
91
// deterministic output.
95
- for list in state. deps . values_mut ( ) {
92
+ for list in state. cx . unit_dependencies . values_mut ( ) {
96
93
list. sort ( ) ;
97
94
}
98
95
@@ -104,16 +101,16 @@ fn deps_of<'a, 'cfg, 'tmp>(
104
101
state : & mut State < ' a , ' cfg , ' tmp > ,
105
102
unit_for : UnitFor ,
106
103
) -> CargoResult < ( ) > {
107
- // Currently the `deps ` map does not include `unit_for`. This should
104
+ // Currently the `unit_dependencies ` map does not include `unit_for`. This should
108
105
// be safe for now. `TestDependency` only exists to clear the `panic`
109
106
// flag, and you'll never ask for a `unit` with `panic` set as a
110
107
// `TestDependency`. `CustomBuild` should also be fine since if the
111
108
// requested unit's settings are the same as `Any`, `CustomBuild` can't
112
109
// affect anything else in the hierarchy.
113
- if !state. deps . contains_key ( unit) {
110
+ if !state. cx . unit_dependencies . contains_key ( unit) {
114
111
let unit_deps = compute_deps ( unit, state, unit_for) ?;
115
112
let to_insert: Vec < _ > = unit_deps. iter ( ) . map ( |& ( unit, _) | unit) . collect ( ) ;
116
- state. deps . insert ( * unit, to_insert) ;
113
+ state. cx . unit_dependencies . insert ( * unit, to_insert) ;
117
114
for ( unit, unit_for) in unit_deps {
118
115
deps_of ( & unit, state, unit_for) ?;
119
116
}
@@ -131,13 +128,13 @@ fn compute_deps<'a, 'cfg, 'tmp>(
131
128
unit_for : UnitFor ,
132
129
) -> CargoResult < Vec < ( Unit < ' a > , UnitFor ) > > {
133
130
if unit. mode . is_run_custom_build ( ) {
134
- return compute_deps_custom_build ( unit, state. bcx ) ;
131
+ return compute_deps_custom_build ( unit, state. cx . bcx ) ;
135
132
} else if unit. mode . is_doc ( ) && !unit. mode . is_any_test ( ) {
136
133
// Note: this does not include doc test.
137
134
return compute_deps_doc ( unit, state) ;
138
135
}
139
136
140
- let bcx = state. bcx ;
137
+ let bcx = state. cx . bcx ;
141
138
let id = unit. pkg . package_id ( ) ;
142
139
let deps = bcx. resolve . deps ( id) . filter ( |& ( _id, deps) | {
143
140
assert ! ( !deps. is_empty( ) ) ;
@@ -295,7 +292,7 @@ fn compute_deps_doc<'a, 'cfg, 'tmp>(
295
292
unit : & Unit < ' a > ,
296
293
state : & mut State < ' a , ' cfg , ' tmp > ,
297
294
) -> CargoResult < Vec < ( Unit < ' a > , UnitFor ) > > {
298
- let bcx = state. bcx ;
295
+ let bcx = state. cx . bcx ;
299
296
let deps = bcx
300
297
. resolve
301
298
. deps ( unit. pkg . package_id ( ) )
@@ -448,7 +445,7 @@ fn connect_run_custom_build_deps(state: &mut State<'_, '_, '_>) {
448
445
// have the build script as the key and the library would be in the
449
446
// value's set.
450
447
let mut reverse_deps = HashMap :: new ( ) ;
451
- for ( unit, deps) in state. deps . iter ( ) {
448
+ for ( unit, deps) in state. cx . unit_dependencies . iter ( ) {
452
449
for dep in deps {
453
450
if dep. mode == CompileMode :: RunCustomBuild {
454
451
reverse_deps
@@ -469,7 +466,8 @@ fn connect_run_custom_build_deps(state: &mut State<'_, '_, '_>) {
469
466
// `dep_build_script` to manufacture an appropriate build script unit to
470
467
// depend on.
471
468
for unit in state
472
- . deps
469
+ . cx
470
+ . unit_dependencies
473
471
. keys ( )
474
472
. filter ( |k| k. mode == CompileMode :: RunCustomBuild )
475
473
{
@@ -480,13 +478,13 @@ fn connect_run_custom_build_deps(state: &mut State<'_, '_, '_>) {
480
478
481
479
let to_add = reverse_deps
482
480
. iter ( )
483
- . flat_map ( |reverse_dep| state. deps [ reverse_dep] . iter ( ) )
481
+ . flat_map ( |reverse_dep| state. cx . unit_dependencies [ reverse_dep] . iter ( ) )
484
482
. filter ( |other| {
485
483
other. pkg != unit. pkg
486
484
&& other. target . linkable ( )
487
485
&& other. pkg . manifest ( ) . links ( ) . is_some ( )
488
486
} )
489
- . filter_map ( |other| dep_build_script ( other, state. bcx ) . map ( |p| p. 0 ) )
487
+ . filter_map ( |other| dep_build_script ( other, state. cx . bcx ) . map ( |p| p. 0 ) )
490
488
. collect :: < HashSet < _ > > ( ) ;
491
489
492
490
if !to_add. is_empty ( ) {
@@ -497,21 +495,39 @@ fn connect_run_custom_build_deps(state: &mut State<'_, '_, '_>) {
497
495
498
496
// And finally, add in all the missing dependencies!
499
497
for ( unit, new_deps) in new_deps {
500
- state. deps . get_mut ( & unit) . unwrap ( ) . extend ( new_deps) ;
498
+ state
499
+ . cx
500
+ . unit_dependencies
501
+ . get_mut ( & unit)
502
+ . unwrap ( )
503
+ . extend ( new_deps) ;
504
+ }
505
+ }
506
+
507
+ /// Records the list of units which are required to emit metadata.
508
+ ///
509
+ /// Units which depend only on the metadata of others requires the others to
510
+ /// actually produce metadata, so we'll record that here.
511
+ fn record_units_requiring_metadata ( cx : & mut Context < ' _ , ' _ > ) {
512
+ for ( key, deps) in cx. unit_dependencies . iter ( ) {
513
+ for dep in deps {
514
+ if cx. only_requires_rmeta ( key, dep) {
515
+ cx. rmeta_required . insert ( * dep) ;
516
+ }
517
+ }
501
518
}
502
519
}
503
520
504
521
impl < ' a , ' cfg , ' tmp > State < ' a , ' cfg , ' tmp > {
505
522
fn get ( & mut self , id : PackageId ) -> CargoResult < Option < & ' a Package > > {
506
- let mut pkgs = self . pkgs . borrow_mut ( ) ;
507
- if let Some ( pkg) = pkgs. get ( & id) {
523
+ if let Some ( pkg) = self . cx . package_cache . get ( & id) {
508
524
return Ok ( Some ( pkg) ) ;
509
525
}
510
526
if !self . waiting_on_download . insert ( id) {
511
527
return Ok ( None ) ;
512
528
}
513
529
if let Some ( pkg) = self . downloads . start ( id) ? {
514
- pkgs . insert ( id, pkg) ;
530
+ self . cx . package_cache . insert ( id, pkg) ;
515
531
self . waiting_on_download . remove ( & id) ;
516
532
return Ok ( Some ( pkg) ) ;
517
533
}
@@ -531,7 +547,7 @@ impl<'a, 'cfg, 'tmp> State<'a, 'cfg, 'tmp> {
531
547
loop {
532
548
let pkg = self . downloads . wait ( ) ?;
533
549
self . waiting_on_download . remove ( & pkg. package_id ( ) ) ;
534
- self . pkgs . borrow_mut ( ) . insert ( pkg. package_id ( ) , pkg) ;
550
+ self . cx . package_cache . insert ( pkg. package_id ( ) , pkg) ;
535
551
536
552
// Arbitrarily choose that 5 or more packages concurrently download
537
553
// is a good enough number to "fill the network pipe". If we have
0 commit comments