@@ -10,48 +10,78 @@ use crate::core::{PackageId, PackageSet, Resolve, Workspace};
10
10
use crate :: ops:: { self , Packages } ;
11
11
use crate :: util:: errors:: CargoResult ;
12
12
13
+ use std:: borrow:: Borrow ;
13
14
use std:: collections:: { HashMap , HashSet } ;
15
+ use std:: hash:: Hash ;
14
16
use std:: path:: PathBuf ;
15
17
16
18
use super :: BuildConfig ;
17
19
18
- fn std_crates < ' a > ( crates : & ' a [ String ] , default : & ' static str , units : & [ Unit ] ) -> HashSet < & ' a str > {
19
- let mut crates = HashSet :: from_iter ( crates. iter ( ) . map ( |s| s. as_str ( ) ) ) ;
20
+ fn add_default_std_crates < T : Borrow < str > + From < & ' static str > + Eq + Hash > (
21
+ crates : & mut HashSet < T > ,
22
+ default : & ' static str ,
23
+ include_libtest : bool ,
24
+ ) {
20
25
// This is a temporary hack until there is a more principled way to
21
26
// declare dependencies in Cargo.toml.
22
27
if crates. is_empty ( ) {
23
- crates. insert ( default) ;
28
+ crates. insert ( default. into ( ) ) ;
24
29
}
25
30
if crates. contains ( "std" ) {
26
- crates. insert ( "core" ) ;
27
- crates. insert ( "alloc" ) ;
28
- crates. insert ( "proc_macro" ) ;
29
- crates. insert ( "panic_unwind" ) ;
30
- crates. insert ( "compiler_builtins" ) ;
31
- // Only build libtest if it looks like it is needed (libtest depends on libstd)
32
- // If we know what units we're building, we can filter for libtest depending on the jobs.
33
- if units
34
- . iter ( )
35
- . any ( |unit| unit. mode . is_rustc_test ( ) && unit. target . harness ( ) )
36
- {
37
- crates. insert ( "test" ) ;
31
+ crates. insert ( "core" . into ( ) ) ;
32
+ crates. insert ( "alloc" . into ( ) ) ;
33
+ crates. insert ( "proc_macro" . into ( ) ) ;
34
+ crates. insert ( "panic_unwind" . into ( ) ) ;
35
+ crates. insert ( "compiler_builtins" . into ( ) ) ;
36
+ if include_libtest {
37
+ crates. insert ( "test" . into ( ) ) ;
38
38
}
39
39
} else if crates. contains ( "core" ) {
40
- crates. insert ( "compiler_builtins" ) ;
40
+ crates. insert ( "compiler_builtins" . into ( ) ) ;
41
41
}
42
+ }
43
+
44
+ fn std_crates (
45
+ target_data : & RustcTargetData < ' _ > ,
46
+ cli_crates : Option < & [ String ] > ,
47
+ include_libtest : bool ,
48
+ ) -> HashMap < CompileKind , HashSet < String > > {
49
+ let mut map = HashMap :: new ( ) ;
50
+ for kind in target_data. all_kinds ( ) . chain ( [ CompileKind :: Host ] ) {
51
+ let requested_crates = if let Some ( crates) = & target_data. target_config ( kind) . build_std {
52
+ crates. val . as_slice ( )
53
+ } else if let Some ( cli_crates) = cli_crates {
54
+ cli_crates
55
+ } else {
56
+ continue ;
57
+ } ;
42
58
43
- crates
59
+ let mut actual_crates = requested_crates
60
+ . iter ( )
61
+ . map ( Clone :: clone)
62
+ . collect :: < HashSet < _ > > ( ) ;
63
+ add_default_std_crates (
64
+ & mut actual_crates,
65
+ if target_data. info ( kind) . maybe_support_std ( ) {
66
+ "std"
67
+ } else {
68
+ "core"
69
+ } ,
70
+ include_libtest,
71
+ ) ;
72
+ map. insert ( kind, actual_crates) ;
73
+ }
74
+ map
44
75
}
45
76
46
77
/// Resolve the standard library dependencies.
47
78
///
48
- /// * `crates ` is the arg value from `-Zbuild-std`.
79
+ /// * `cli_crates ` is the arg value from `-Zbuild-std`.
49
80
pub fn resolve_std < ' gctx > (
50
81
ws : & Workspace < ' gctx > ,
51
82
target_data : & mut RustcTargetData < ' gctx > ,
52
83
build_config : & BuildConfig ,
53
- crates : & [ String ] ,
54
- kinds : & [ CompileKind ] ,
84
+ cli_crates : Option < & [ String ] > ,
55
85
) -> CargoResult < ( PackageSet < ' gctx > , Resolve , ResolvedFeatures ) > {
56
86
if build_config. build_plan {
57
87
ws. gctx ( )
@@ -69,31 +99,32 @@ pub fn resolve_std<'gctx>(
69
99
// `[dev-dependencies]`. No need for us to generate a `Resolve` which has
70
100
// those included because we'll never use them anyway.
71
101
std_ws. set_require_optional_deps ( false ) ;
102
+ let mut build_std_features = HashSet :: new ( ) ;
72
103
let specs = {
73
- // If there is anything looks like needing std, resolve with it.
74
- // If not, we assume only `core` maye be needed, as `core the most fundamental crate.
75
- //
76
- // This may need a UI overhaul if `build-std` wants to fully support multi-targets.
77
- let maybe_std = kinds
78
- . iter ( )
79
- . any ( |kind| target_data. info ( * kind) . maybe_support_std ( ) ) ;
80
- let mut crates = std_crates ( crates, if maybe_std { "std" } else { "core" } , & [ ] ) ;
104
+ let mut set = HashSet :: new ( ) ;
105
+ for ( compile_kind, new_set) in std_crates ( target_data, cli_crates, false ) {
106
+ set. extend ( new_set) ;
107
+ if let Some ( features) = & target_data. target_config ( compile_kind) . build_std_features {
108
+ build_std_features. extend ( features. val . as_slice ( ) . iter ( ) . map ( String :: clone) ) ;
109
+ } else if let Some ( features) = & gctx. cli_unstable ( ) . build_std_features {
110
+ build_std_features. extend ( features. iter ( ) . map ( String :: clone) ) ;
111
+ } else {
112
+ build_std_features
113
+ . extend ( [ "panic-unwind" , "backtrace" , "default" ] . map ( String :: from) ) ;
114
+ }
115
+ }
81
116
// `sysroot` is not in the default set because it is optional, but it needs
82
- // to be part of the resolve in case we do need it or `libtest`.
83
- crates . insert ( "sysroot" ) ;
84
- let specs = Packages :: Packages ( crates . into_iter ( ) . map ( Into :: into ) . collect ( ) ) ;
117
+ // to be part of the resolve in case we do need it for `libtest`.
118
+ set . insert ( "sysroot" . into ( ) ) ;
119
+ let specs = Packages :: Packages ( set . into_iter ( ) . collect ( ) ) ;
85
120
specs. to_package_id_specs ( & std_ws) ?
86
121
} ;
87
- let features = match & gctx. cli_unstable ( ) . build_std_features {
88
- Some ( list) => list. clone ( ) ,
89
- None => vec ! [
90
- "panic-unwind" . to_string( ) ,
91
- "backtrace" . to_string( ) ,
92
- "default" . to_string( ) ,
93
- ] ,
94
- } ;
122
+
123
+ let build_std_features = build_std_features. into_iter ( ) . collect :: < Vec < _ > > ( ) ;
95
124
let cli_features = CliFeatures :: from_command_line (
96
- & features, /*all_features*/ false , /*uses_default_features*/ false ,
125
+ & build_std_features,
126
+ /*all_features*/ false ,
127
+ /*uses_default_features*/ false ,
97
128
) ?;
98
129
let dry_run = false ;
99
130
let resolve = ops:: resolve_ws_with_opts (
@@ -118,76 +149,62 @@ pub fn resolve_std<'gctx>(
118
149
/// * `crates` is the arg value from `-Zbuild-std`.
119
150
/// * `units` is the root units of the build.
120
151
pub fn generate_std_roots (
121
- crates : & [ String ] ,
152
+ cli_crates : Option < & [ String ] > ,
122
153
units : & [ Unit ] ,
123
154
std_resolve : & Resolve ,
124
155
std_features : & ResolvedFeatures ,
125
- kinds : & [ CompileKind ] ,
126
156
package_set : & PackageSet < ' _ > ,
127
157
interner : & UnitInterner ,
128
158
profiles : & Profiles ,
129
159
target_data : & RustcTargetData < ' _ > ,
130
160
) -> CargoResult < HashMap < CompileKind , Vec < Unit > > > {
131
161
// Generate a map of Units for each kind requested.
132
- let mut ret = HashMap :: new ( ) ;
133
- let ( maybe_std, maybe_core) : ( Vec < & CompileKind > , Vec < _ > ) = kinds
162
+ let mut ret: HashMap < CompileKind , Vec < Unit > > = HashMap :: new ( ) ;
163
+ // Only build libtest if it looks like it is needed (libtest depends on libstd)
164
+ // If we know what units we're building, we can filter for libtest depending on the jobs.
165
+ let include_libtest = units
134
166
. iter ( )
135
- . partition ( |kind| target_data. info ( * * kind) . maybe_support_std ( ) ) ;
136
- for ( default_crate, kinds) in [ ( "core" , maybe_core) , ( "std" , maybe_std) ] {
137
- if kinds. is_empty ( ) {
138
- continue ;
139
- }
140
- generate_roots (
141
- & mut ret,
142
- default_crate,
143
- crates,
144
- units,
145
- std_resolve,
146
- std_features,
147
- & kinds,
148
- package_set,
149
- interner,
150
- profiles,
151
- target_data,
152
- ) ?;
153
- }
167
+ . any ( |unit| unit. mode . is_rustc_test ( ) && unit. target . harness ( ) ) ;
168
+ let crates = std_crates ( target_data, cli_crates, include_libtest) ;
154
169
155
- Ok ( ret)
156
- }
170
+ let all_crates = crates
171
+ . values ( )
172
+ . flat_map ( |set| set)
173
+ . map ( |s| s. as_str ( ) )
174
+ . collect :: < HashSet < _ > > ( ) ;
175
+ // collect as `Vec` for stable order
176
+ let all_crates = all_crates. into_iter ( ) . collect :: < Vec < _ > > ( ) ;
177
+ let std_ids = all_crates
178
+ . iter ( )
179
+ . map ( |crate_name| {
180
+ std_resolve
181
+ . query ( crate_name)
182
+ . map ( |pkg_id| ( pkg_id, * crate_name) )
183
+ } )
184
+ . collect :: < CargoResult < HashMap < PackageId , & str > > > ( ) ?;
185
+ let std_pkgs = package_set. get_many ( std_ids. keys ( ) . copied ( ) ) ?;
157
186
158
- fn generate_roots (
159
- ret : & mut HashMap < CompileKind , Vec < Unit > > ,
160
- default : & ' static str ,
161
- crates : & [ String ] ,
162
- units : & [ Unit ] ,
163
- std_resolve : & Resolve ,
164
- std_features : & ResolvedFeatures ,
165
- kinds : & [ & CompileKind ] ,
166
- package_set : & PackageSet < ' _ > ,
167
- interner : & UnitInterner ,
168
- profiles : & Profiles ,
169
- target_data : & RustcTargetData < ' _ > ,
170
- ) -> CargoResult < ( ) > {
171
- let std_ids = std_crates ( crates, default, units)
187
+ // a map of the requested std crate and its actual package.
188
+ let std_pkgs = std_pkgs
172
189
. iter ( )
173
- . map ( |crate_name| std_resolve. query ( crate_name) )
174
- . collect :: < CargoResult < Vec < PackageId > > > ( ) ?;
175
- let std_pkgs = package_set. get_many ( std_ids) ?;
190
+ . map ( |pkg| ( * std_ids. get ( & pkg. package_id ( ) ) . unwrap ( ) , * pkg) )
191
+ . collect :: < HashMap < _ , _ > > ( ) ;
176
192
177
- for pkg in std_pkgs {
178
- let lib = pkg
179
- . targets ( )
180
- . iter ( )
181
- . find ( |t| t. is_lib ( ) )
182
- . expect ( "std has a lib" ) ;
183
- // I don't think we need to bother with Check here, the difference
184
- // in time is minimal, and the difference in caching is
185
- // significant.
186
- let mode = CompileMode :: Build ;
187
- let features = std_features. activated_features ( pkg. package_id ( ) , FeaturesFor :: NormalOrDev ) ;
188
- for kind in kinds {
189
- let kind = * * kind;
190
- let list = ret. entry ( kind) . or_insert_with ( Vec :: new) ;
193
+ for ( & kind, crates) in & crates {
194
+ let list = ret. entry ( kind) . or_default ( ) ;
195
+ for krate in crates {
196
+ let pkg = std_pkgs. get ( krate. as_str ( ) ) . unwrap ( ) ;
197
+ let lib = pkg
198
+ . targets ( )
199
+ . iter ( )
200
+ . find ( |t| t. is_lib ( ) )
201
+ . expect ( "std has a lib" ) ;
202
+ // I don't think we need to bother with Check here, the difference
203
+ // in time is minimal, and the difference in caching is
204
+ // significant.
205
+ let mode = CompileMode :: Build ;
206
+ let features =
207
+ std_features. activated_features ( pkg. package_id ( ) , FeaturesFor :: NormalOrDev ) ;
191
208
let unit_for = UnitFor :: new_normal ( kind) ;
192
209
let profile = profiles. get_profile (
193
210
pkg. package_id ( ) ,
@@ -213,7 +230,8 @@ fn generate_roots(
213
230
) ) ;
214
231
}
215
232
}
216
- Ok ( ( ) )
233
+
234
+ Ok ( ret)
217
235
}
218
236
219
237
fn detect_sysroot_src_path ( target_data : & RustcTargetData < ' _ > ) -> CargoResult < PathBuf > {
0 commit comments