]>
Commit | Line | Data |
---|---|---|
2599c34d | 1 | //! The Cargo "compile" operation. |
64ff29ff | 2 | //! |
2599c34d EH |
3 | //! This module contains the entry point for starting the compilation process |
4 | //! for commands like `build`, `test`, `doc`, `rustc`, etc. | |
64ff29ff | 5 | //! |
2599c34d EH |
6 | //! The `compile` function will do all the work to compile a workspace. A |
7 | //! rough outline is: | |
64ff29ff | 8 | //! |
2599c34d | 9 | //! - Resolve the dependency graph (see `ops::resolve`). |
1f14fa31 EH |
10 | //! - Download any packages needed (see `PackageSet`). Note that dependency |
11 | //! downloads are deferred until `build_unit_dependencies`. | |
2599c34d EH |
12 | //! - Generate a list of top-level "units" of work for the targets the user |
13 | //! requested on the command-line. Each `Unit` corresponds to a compiler | |
14 | //! invocation. This is done in this module (`generate_targets`). | |
15 | //! - Create a `Context` which will perform the following steps: | |
16 | //! - Build the graph of `Unit` dependencies (see | |
17 | //! `core::compiler::context::unit_dependencies`). | |
18 | //! - Prepare the `target` directory (see `Layout`). | |
19 | //! - Create a job queue (see `JobQueue`). The queue checks the | |
20 | //! fingerprint of each `Unit` to determine if it should run or be | |
21 | //! skipped. | |
22 | //! - Execute the queue. Each leaf in the queue's dependency graph is | |
23 | //! executed, and then removed from the graph when finished. This | |
24 | //! repeats until the queue is empty. | |
62bff631 | 25 | |
45ce445c DW |
26 | use std::collections::{BTreeSet, HashMap, HashSet}; |
27 | use std::iter::FromIterator; | |
8cf53bca | 28 | use std::path::PathBuf; |
1ab19a5a | 29 | use std::sync::Arc; |
12af54e1 | 30 | |
1f14fa31 EH |
31 | use crate::core::compiler::standard_lib; |
32 | use crate::core::compiler::unit_dependencies::build_unit_dependencies; | |
e4544466 | 33 | use crate::core::compiler::{BuildConfig, BuildContext, Compilation, Context}; |
ef425b77 | 34 | use crate::core::compiler::{CompileKind, CompileMode, Unit}; |
e4544466 | 35 | use crate::core::compiler::{DefaultExecutor, Executor, UnitInterner}; |
04ddd4d0 | 36 | use crate::core::profiles::{Profiles, UnitFor}; |
e26ef017 | 37 | use crate::core::resolver::{Resolve, ResolveOpts}; |
70bea01b | 38 | use crate::core::{LibKind, Package, PackageSet, Target}; |
04ddd4d0 DW |
39 | use crate::core::{PackageId, PackageIdSpec, TargetKind, Workspace}; |
40 | use crate::ops; | |
12392f6d | 41 | use crate::ops::resolve::WorkspaceResolve; |
04ddd4d0 | 42 | use crate::util::config::Config; |
7d7fe679 | 43 | use crate::util::{closest_msg, profile, CargoResult}; |
50f110a4 | 44 | |
bacb6be3 | 45 | /// Contains information about how a package should be compiled. |
876af7c1 | 46 | #[derive(Debug)] |
2fe0bf83 AC |
47 | pub struct CompileOptions<'a> { |
48 | pub config: &'a Config, | |
08025169 DO |
49 | /// Configuration information for a rustc build |
50 | pub build_config: BuildConfig, | |
9e779198 | 51 | /// Extra features to build for the root package |
bb643cca | 52 | pub features: Vec<String>, |
1f8b3988 DA |
53 | /// Flag whether all available features should be built for the root package |
54 | pub all_features: bool, | |
9e779198 | 55 | /// Flag if the default feature should be built for the root package |
2b46d039 | 56 | pub no_default_features: bool, |
6b32c4d7 | 57 | /// A set of packages to build. |
bb643cca | 58 | pub spec: Packages, |
9e779198 AC |
59 | /// Filter to apply to the root package to select which targets will be |
60 | /// built. | |
bb643cca | 61 | pub filter: CompileFilter, |
1ef954ea | 62 | /// Extra arguments to be passed to rustdoc (single target only) |
bb643cca | 63 | pub target_rustdoc_args: Option<Vec<String>>, |
77bb01ec SL |
64 | /// The specified target will be compiled with all the available arguments, |
65 | /// note that this only accounts for the *final* invocation of rustc | |
bb643cca | 66 | pub target_rustc_args: Option<Vec<String>>, |
1ef954ea EH |
67 | /// Extra arguments passed to all selected targets for rustdoc. |
68 | pub local_rustdoc_args: Option<Vec<String>>, | |
e7ee237c LK |
69 | /// Whether the `--document-private-items` flags was specified and should |
70 | /// be forwarded to `rustdoc`. | |
71 | pub rustdoc_document_private_items: bool, | |
5baac6b3 AK |
72 | /// The directory to copy final artifacts to. Note that even if `out_dir` is |
73 | /// set, a copy of artifacts still could be found a `target/(debug\release)` | |
74 | /// as usual. | |
75 | // Note that, although the cmd-line flag name is `out-dir`, in code we use | |
76 | // `export_dir`, to avoid confusion with out dir at `target/debug/deps`. | |
77 | pub export_dir: Option<PathBuf>, | |
9e779198 AC |
78 | } |
79 | ||
69caa63b | 80 | impl<'a> CompileOptions<'a> { |
072254c3 | 81 | pub fn new(config: &'a Config, mode: CompileMode) -> CargoResult<CompileOptions<'a>> { |
08025169 | 82 | Ok(CompileOptions { |
0247dc42 | 83 | config, |
08025169 | 84 | build_config: BuildConfig::new(config, None, &None, mode)?, |
bb643cca | 85 | features: Vec::new(), |
69caa63b NC |
86 | all_features: false, |
87 | no_default_features: false, | |
bb643cca | 88 | spec: ops::Packages::Packages(Vec::new()), |
1e682848 AC |
89 | filter: CompileFilter::Default { |
90 | required_features_filterable: false, | |
91 | }, | |
69caa63b NC |
92 | target_rustdoc_args: None, |
93 | target_rustc_args: None, | |
1ef954ea | 94 | local_rustdoc_args: None, |
e7ee237c | 95 | rustdoc_document_private_items: false, |
5baac6b3 | 96 | export_dir: None, |
08025169 | 97 | }) |
69caa63b NC |
98 | } |
99 | } | |
100 | ||
bb643cca AK |
101 | #[derive(Clone, PartialEq, Eq, Debug)] |
102 | pub enum Packages { | |
ba7911dd | 103 | Default, |
62c04979 | 104 | All, |
bb643cca AK |
105 | OptOut(Vec<String>), |
106 | Packages(Vec<String>), | |
62c04979 AR |
107 | } |
108 | ||
bb643cca | 109 | impl Packages { |
1e682848 | 110 | pub fn from_flags(all: bool, exclude: Vec<String>, package: Vec<String>) -> CargoResult<Self> { |
ba7911dd SS |
111 | Ok(match (all, exclude.len(), package.len()) { |
112 | (false, 0, 0) => Packages::Default, | |
113 | (false, 0, _) => Packages::Packages(package), | |
3a18c89a | 114 | (false, _, _) => anyhow::bail!("--exclude can only be used together with --workspace"), |
ba7911dd SS |
115 | (true, 0, _) => Packages::All, |
116 | (true, _, _) => Packages::OptOut(exclude), | |
117 | }) | |
7ffd1cfc | 118 | } |
119 | ||
b8b7faee | 120 | pub fn to_package_id_specs(&self, ws: &Workspace<'_>) -> CargoResult<Vec<PackageIdSpec>> { |
d347908d | 121 | let specs = match self { |
dae87a26 E |
122 | Packages::All => ws |
123 | .members() | |
1e682848 AC |
124 | .map(Package::package_id) |
125 | .map(PackageIdSpec::from_package_id) | |
126 | .collect(), | |
45ce445c DW |
127 | Packages::OptOut(opt_out) => { |
128 | let mut opt_out = BTreeSet::from_iter(opt_out.iter().cloned()); | |
129 | let packages = ws | |
130 | .members() | |
131 | .filter(|pkg| !opt_out.remove(pkg.name().as_str())) | |
132 | .map(Package::package_id) | |
133 | .map(PackageIdSpec::from_package_id) | |
134 | .collect(); | |
135 | if !opt_out.is_empty() { | |
136 | ws.config().shell().warn(format!( | |
137 | "excluded package(s) {} not found in workspace `{}`", | |
f16efff1 AC |
138 | opt_out |
139 | .iter() | |
140 | .map(|x| x.as_ref()) | |
141 | .collect::<Vec<_>>() | |
142 | .join(", "), | |
45ce445c DW |
143 | ws.root().display(), |
144 | ))?; | |
145 | } | |
146 | packages | |
f16efff1 | 147 | } |
d347908d | 148 | Packages::Packages(packages) if packages.is_empty() => { |
037a879d EH |
149 | vec![PackageIdSpec::from_package_id(ws.current()?.package_id())] |
150 | } | |
d347908d | 151 | Packages::Packages(packages) => packages |
1e682848 AC |
152 | .iter() |
153 | .map(|p| PackageIdSpec::parse(p)) | |
154 | .collect::<CargoResult<Vec<_>>>()?, | |
dae87a26 E |
155 | Packages::Default => ws |
156 | .default_members() | |
1e682848 AC |
157 | .map(Package::package_id) |
158 | .map(PackageIdSpec::from_package_id) | |
159 | .collect(), | |
6b32c4d7 | 160 | }; |
68a681ff | 161 | if specs.is_empty() { |
691f95de | 162 | if ws.is_virtual() { |
3a18c89a | 163 | anyhow::bail!( |
1e682848 AC |
164 | "manifest path `{}` contains no package: The manifest is virtual, \ |
165 | and the workspace has no members.", | |
166 | ws.root().display() | |
167 | ) | |
05b896ac | 168 | } |
3a18c89a | 169 | anyhow::bail!("no packages to compile") |
68a681ff | 170 | } |
6b32c4d7 AK |
171 | Ok(specs) |
172 | } | |
fa54a794 | 173 | |
b8b7faee | 174 | pub fn get_packages<'ws>(&self, ws: &'ws Workspace<'_>) -> CargoResult<Vec<&'ws Package>> { |
fa54a794 EH |
175 | let packages: Vec<_> = match self { |
176 | Packages::Default => ws.default_members().collect(), | |
177 | Packages::All => ws.members().collect(), | |
d347908d | 178 | Packages::OptOut(opt_out) => ws |
fa54a794 EH |
179 | .members() |
180 | .filter(|pkg| !opt_out.iter().any(|name| pkg.name().as_str() == name)) | |
181 | .collect(), | |
d347908d | 182 | Packages::Packages(packages) => packages |
fa54a794 EH |
183 | .iter() |
184 | .map(|name| { | |
185 | ws.members() | |
186 | .find(|pkg| pkg.name().as_str() == name) | |
187 | .ok_or_else(|| { | |
3a18c89a | 188 | anyhow::format_err!( |
54c42142 DW |
189 | "package `{}` is not a member of the workspace", |
190 | name | |
191 | ) | |
fa54a794 | 192 | }) |
dae87a26 E |
193 | }) |
194 | .collect::<CargoResult<Vec<_>>>()?, | |
fa54a794 EH |
195 | }; |
196 | Ok(packages) | |
197 | } | |
44c535ab EH |
198 | |
199 | /// Returns whether or not the user needs to pass a `-p` flag to target a | |
200 | /// specific package in the workspace. | |
201 | pub fn needs_spec_flag(&self, ws: &Workspace<'_>) -> bool { | |
202 | match self { | |
203 | Packages::Default => ws.default_members().count() > 1, | |
204 | Packages::All => ws.members().count() > 1, | |
205 | Packages::Packages(_) => true, | |
206 | Packages::OptOut(_) => true, | |
207 | } | |
208 | } | |
6b32c4d7 AK |
209 | } |
210 | ||
aef99e0e DW |
211 | #[derive(Debug, PartialEq, Eq)] |
212 | pub enum LibRule { | |
213 | /// Include the library, fail if not present | |
214 | True, | |
215 | /// Include the library if present | |
216 | Default, | |
217 | /// Exclude the library | |
218 | False, | |
219 | } | |
220 | ||
bb643cca AK |
221 | #[derive(Debug)] |
222 | pub enum FilterRule { | |
2a82378a | 223 | All, |
bb643cca | 224 | Just(Vec<String>), |
2a82378a BW |
225 | } |
226 | ||
876af7c1 | 227 | #[derive(Debug)] |
bb643cca | 228 | pub enum CompileFilter { |
6344db05 | 229 | Default { |
25e50b58 JB |
230 | /// Flag whether targets can be safely skipped when required-features are not satisfied. |
231 | required_features_filterable: bool, | |
232 | }, | |
9e779198 | 233 | Only { |
b9497ab2 | 234 | all_targets: bool, |
aef99e0e | 235 | lib: LibRule, |
bb643cca AK |
236 | bins: FilterRule, |
237 | examples: FilterRule, | |
238 | tests: FilterRule, | |
239 | benches: FilterRule, | |
1e682848 | 240 | }, |
a1980dc7 YKCL |
241 | } |
242 | ||
1e682848 AC |
243 | pub fn compile<'a>( |
244 | ws: &Workspace<'a>, | |
245 | options: &CompileOptions<'a>, | |
a340ba0b | 246 | ) -> CargoResult<Compilation<'a>> { |
b8b7faee | 247 | let exec: Arc<dyn Executor> = Arc::new(DefaultExecutor); |
689f412c | 248 | compile_with_exec(ws, options, &exec) |
8c3b3605 NC |
249 | } |
250 | ||
4a64d05e | 251 | /// Like `compile` but allows specifying a custom `Executor` that will be able to intercept build |
d70f91ee | 252 | /// calls and add custom logic. `compile` uses `DefaultExecutor` which just passes calls through. |
1e682848 AC |
253 | pub fn compile_with_exec<'a>( |
254 | ws: &Workspace<'a>, | |
255 | options: &CompileOptions<'a>, | |
b8b7faee | 256 | exec: &Arc<dyn Executor>, |
a340ba0b | 257 | ) -> CargoResult<Compilation<'a>> { |
688a4fa6 | 258 | ws.emit_warnings()?; |
8a301589 | 259 | compile_ws(ws, options, exec) |
9fba127e AC |
260 | } |
261 | ||
1e682848 AC |
262 | pub fn compile_ws<'a>( |
263 | ws: &Workspace<'a>, | |
1e682848 | 264 | options: &CompileOptions<'a>, |
b8b7faee | 265 | exec: &Arc<dyn Executor>, |
a340ba0b | 266 | ) -> CargoResult<Compilation<'a>> { |
1e682848 AC |
267 | let CompileOptions { |
268 | config, | |
08025169 | 269 | ref build_config, |
1e682848 AC |
270 | ref spec, |
271 | ref features, | |
272 | all_features, | |
273 | no_default_features, | |
1e682848 AC |
274 | ref filter, |
275 | ref target_rustdoc_args, | |
276 | ref target_rustc_args, | |
1ef954ea | 277 | ref local_rustdoc_args, |
e7ee237c | 278 | rustdoc_document_private_items, |
5baac6b3 | 279 | ref export_dir, |
1e682848 | 280 | } = *options; |
3656bec8 | 281 | |
d17ccec2 HY |
282 | match build_config.mode { |
283 | CompileMode::Test | |
284 | | CompileMode::Build | |
285 | | CompileMode::Check { .. } | |
286 | | CompileMode::Bench | |
287 | | CompileMode::RunCustomBuild => { | |
288 | if std::env::var("RUST_FLAGS").is_ok() { | |
289 | config.shell().warn( | |
290 | "Cargo does not read `RUST_FLAGS` environment variable. Did you mean `RUSTFLAGS`?", | |
291 | )?; | |
292 | } | |
293 | } | |
294 | CompileMode::Doc { .. } | CompileMode::Doctest => { | |
295 | if std::env::var("RUSTDOC_FLAGS").is_ok() { | |
296 | config.shell().warn( | |
297 | "Cargo does not read `RUSTDOC_FLAGS` environment variable. Did you mean `RUSTDOCFLAGS`?" | |
298 | )?; | |
299 | } | |
300 | } | |
301 | } | |
302 | ||
77ee608d EH |
303 | let profiles = Profiles::new( |
304 | ws.profiles(), | |
305 | config, | |
306 | build_config.requested_profile, | |
307 | ws.features(), | |
308 | )?; | |
47007d97 | 309 | |
8947ed1f | 310 | let specs = spec.to_package_id_specs(ws)?; |
e26ef017 EH |
311 | let dev_deps = ws.require_optional_deps() || filter.need_dev_deps(build_config.mode); |
312 | let opts = ResolveOpts::new(dev_deps, features, all_features, !no_default_features); | |
313 | let resolve = ops::resolve_ws_with_opts(ws, opts, &specs)?; | |
12392f6d EH |
314 | let WorkspaceResolve { |
315 | mut pkg_set, | |
316 | workspace_resolve, | |
317 | targeted_resolve: resolve, | |
318 | } = resolve; | |
1f14fa31 EH |
319 | |
320 | let std_resolve = if let Some(crates) = &config.cli_unstable().build_std { | |
3afb5d7d EH |
321 | if build_config.build_plan { |
322 | config | |
323 | .shell() | |
324 | .warn("-Zbuild-std does not currently fully support --build-plan")?; | |
325 | } | |
ef425b77 | 326 | if build_config.requested_kind.is_host() { |
1f14fa31 EH |
327 | // TODO: This should eventually be fixed. Unfortunately it is not |
328 | // easy to get the host triple in BuildConfig. Consider changing | |
329 | // requested_target to an enum, or some other approach. | |
3a18c89a | 330 | anyhow::bail!("-Zbuild-std requires --target"); |
1f14fa31 | 331 | } |
70bea01b AC |
332 | let (mut std_package_set, std_resolve) = standard_lib::resolve_std(ws, crates)?; |
333 | remove_dylib_crate_type(&mut std_package_set)?; | |
12392f6d | 334 | pkg_set.add_set(std_package_set); |
1f14fa31 EH |
335 | Some(std_resolve) |
336 | } else { | |
337 | None | |
338 | }; | |
9c296792 | 339 | |
1f14fa31 EH |
340 | // Find the packages in the resolver that the user wants to build (those |
341 | // passed in with `-p` or the defaults from the workspace), and convert | |
342 | // Vec<PackageIdSpec> to a Vec<&PackageId>. | |
dae87a26 E |
343 | let to_build_ids = specs |
344 | .iter() | |
12392f6d | 345 | .map(|s| s.query(resolve.iter())) |
e2637b65 | 346 | .collect::<CargoResult<Vec<_>>>()?; |
1f14fa31 EH |
347 | // Now get the `Package` for each `PackageId`. This may trigger a download |
348 | // if the user specified `-p` for a dependency that is not downloaded. | |
349 | // Dependencies will be downloaded during build_unit_dependencies. | |
12392f6d | 350 | let mut to_builds = pkg_set.get_many(to_build_ids)?; |
0ea0c8ba | 351 | |
7b1a0dc5 AC |
352 | // The ordering here affects some error messages coming out of cargo, so |
353 | // let's be test and CLI friendly by always printing in the same order if | |
354 | // there's an error. | |
355 | to_builds.sort_by_key(|p| p.package_id()); | |
356 | ||
357 | for pkg in to_builds.iter() { | |
1f14fa31 | 358 | pkg.manifest().print_teapot(config); |
786848a0 EH |
359 | |
360 | if build_config.mode.is_any_test() | |
361 | && !ws.is_member(pkg) | |
362 | && pkg.dependencies().iter().any(|dep| !dep.is_transitive()) | |
363 | { | |
3a18c89a | 364 | anyhow::bail!( |
786848a0 EH |
365 | "package `{}` cannot be tested because it requires dev-dependencies \ |
366 | and is not a member of the workspace", | |
367 | pkg.name() | |
368 | ); | |
369 | } | |
7b1a0dc5 | 370 | } |
f0647ea2 | 371 | |
575d6e81 EH |
372 | let (extra_args, extra_args_name) = match (target_rustc_args, target_rustdoc_args) { |
373 | (&Some(ref args), _) => (Some(args.clone()), "rustc"), | |
374 | (_, &Some(ref args)) => (Some(args.clone()), "rustdoc"), | |
375 | _ => (None, ""), | |
f0647ea2 | 376 | }; |
b3ade7c7 | 377 | |
575d6e81 EH |
378 | if extra_args.is_some() && to_builds.len() != 1 { |
379 | panic!( | |
380 | "`{}` should not accept multiple `-p` flags", | |
381 | extra_args_name | |
382 | ); | |
383 | } | |
384 | ||
12392f6d | 385 | profiles.validate_packages( |
77ee608d | 386 | ws.profiles(), |
12392f6d EH |
387 | &mut config.shell(), |
388 | workspace_resolve.as_ref().unwrap_or(&resolve), | |
389 | )?; | |
a0a880c3 | 390 | |
e4544466 AC |
391 | let interner = UnitInterner::new(); |
392 | let mut bcx = BuildContext::new( | |
393 | ws, | |
12392f6d | 394 | &pkg_set, |
e4544466 AC |
395 | config, |
396 | build_config, | |
397 | profiles, | |
398 | &interner, | |
399 | HashMap::new(), | |
400 | )?; | |
575d6e81 | 401 | let units = generate_targets( |
73660740 | 402 | ws, |
575d6e81 EH |
403 | &to_builds, |
404 | filter, | |
ef425b77 | 405 | build_config.requested_kind, |
12392f6d | 406 | &resolve, |
e4544466 | 407 | &bcx, |
575d6e81 EH |
408 | )?; |
409 | ||
1f14fa31 | 410 | let std_roots = if let Some(crates) = &config.cli_unstable().build_std { |
3ba9de85 EH |
411 | // Only build libtest if it looks like it is needed. |
412 | let mut crates = crates.clone(); | |
413 | if !crates.iter().any(|c| c == "test") | |
414 | && units | |
415 | .iter() | |
416 | .any(|unit| unit.mode.is_rustc_test() && unit.target.harness()) | |
417 | { | |
18a89732 PO |
418 | // Only build libtest when libstd is built (libtest depends on libstd) |
419 | if crates.iter().any(|c| c == "std") { | |
420 | crates.push("test".to_string()); | |
421 | } | |
3ba9de85 | 422 | } |
593a02f2 AC |
423 | standard_lib::generate_std_roots( |
424 | &bcx, | |
425 | &crates, | |
426 | std_resolve.as_ref().unwrap(), | |
ef425b77 | 427 | build_config.requested_kind, |
593a02f2 | 428 | )? |
1f14fa31 EH |
429 | } else { |
430 | Vec::new() | |
431 | }; | |
432 | ||
575d6e81 EH |
433 | if let Some(args) = extra_args { |
434 | if units.len() != 1 { | |
3a18c89a | 435 | anyhow::bail!( |
575d6e81 | 436 | "extra arguments to `{}` can only be passed to one \ |
f7c91ba6 AR |
437 | target, consider filtering\nthe package by passing, \ |
438 | e.g., `--lib` or `--bin NAME` to specify a single target", | |
575d6e81 EH |
439 | extra_args_name |
440 | ); | |
8a8ea1e8 | 441 | } |
e4544466 | 442 | bcx.extra_compiler_args.insert(units[0], args); |
1ef954ea | 443 | } |
e7ee237c LK |
444 | for unit in &units { |
445 | if unit.mode.is_doc() || unit.mode.is_doc_test() { | |
446 | let mut extra_args = local_rustdoc_args.clone(); | |
447 | ||
448 | // Add `--document-private-items` rustdoc flag if requested or if | |
449 | // the target is a binary. Binary crates get their private items | |
450 | // documented by default. | |
451 | if rustdoc_document_private_items || unit.target.is_bin() { | |
a6a395c6 | 452 | let mut args = extra_args.take().unwrap_or_else(|| vec![]); |
e7ee237c LK |
453 | args.push("--document-private-items".into()); |
454 | extra_args = Some(args); | |
455 | } | |
456 | ||
457 | if let Some(args) = extra_args { | |
e4544466 | 458 | bcx.extra_compiler_args.insert(*unit, args.clone()); |
1ef954ea EH |
459 | } |
460 | } | |
b3ade7c7 | 461 | } |
575d6e81 | 462 | |
12392f6d EH |
463 | let unit_dependencies = |
464 | build_unit_dependencies(&bcx, &resolve, std_resolve.as_ref(), &units, &std_roots)?; | |
9a8d695b | 465 | |
00d325db | 466 | let ret = { |
4f12a2b5 | 467 | let _p = profile::start("compiling"); |
ef425b77 | 468 | let cx = Context::new(config, &bcx, unit_dependencies, build_config.requested_kind)?; |
ef0b4776 | 469 | cx.compile(&units, export_dir.clone(), exec)? |
0484cd88 | 470 | }; |
8b840393 | 471 | |
385b54b3 | 472 | Ok(ret) |
62bff631 | 473 | } |
51c9cf0f | 474 | |
bb643cca AK |
475 | impl FilterRule { |
476 | pub fn new(targets: Vec<String>, all: bool) -> FilterRule { | |
2a82378a BW |
477 | if all { |
478 | FilterRule::All | |
479 | } else { | |
480 | FilterRule::Just(targets) | |
481 | } | |
482 | } | |
483 | ||
12307fc2 DW |
484 | pub fn none() -> FilterRule { |
485 | FilterRule::Just(Vec::new()) | |
486 | } | |
487 | ||
2a82378a BW |
488 | fn matches(&self, target: &Target) -> bool { |
489 | match *self { | |
490 | FilterRule::All => true, | |
1e682848 | 491 | FilterRule::Just(ref targets) => targets.iter().any(|x| *x == target.name()), |
2a82378a BW |
492 | } |
493 | } | |
494 | ||
495 | fn is_specific(&self) -> bool { | |
496 | match *self { | |
497 | FilterRule::All => true, | |
bb643cca | 498 | FilterRule::Just(ref targets) => !targets.is_empty(), |
2a82378a BW |
499 | } |
500 | } | |
501 | ||
502 | pub fn try_collect(&self) -> Option<Vec<String>> { | |
503 | match *self { | |
504 | FilterRule::All => None, | |
bb643cca | 505 | FilterRule::Just(ref targets) => Some(targets.clone()), |
2a82378a BW |
506 | } |
507 | } | |
508 | } | |
509 | ||
bb643cca | 510 | impl CompileFilter { |
12307fc2 DW |
511 | /// Construct a CompileFilter from raw command line arguments. |
512 | pub fn from_raw_arguments( | |
1e682848 AC |
513 | lib_only: bool, |
514 | bins: Vec<String>, | |
515 | all_bins: bool, | |
516 | tsts: Vec<String>, | |
517 | all_tsts: bool, | |
518 | exms: Vec<String>, | |
519 | all_exms: bool, | |
520 | bens: Vec<String>, | |
521 | all_bens: bool, | |
522 | all_targets: bool, | |
523 | ) -> CompileFilter { | |
5a59b809 EH |
524 | if all_targets { |
525 | return CompileFilter::new_all_targets(); | |
526 | } | |
f16efff1 AC |
527 | let rule_lib = if lib_only { |
528 | LibRule::True | |
529 | } else { | |
530 | LibRule::False | |
531 | }; | |
2a82378a BW |
532 | let rule_bins = FilterRule::new(bins, all_bins); |
533 | let rule_tsts = FilterRule::new(tsts, all_tsts); | |
534 | let rule_exms = FilterRule::new(exms, all_exms); | |
535 | let rule_bens = FilterRule::new(bens, all_bens); | |
536 | ||
5a59b809 | 537 | CompileFilter::new(rule_lib, rule_bins, rule_tsts, rule_exms, rule_bens) |
12307fc2 DW |
538 | } |
539 | ||
540 | /// Construct a CompileFilter from underlying primitives. | |
541 | pub fn new( | |
aef99e0e | 542 | rule_lib: LibRule, |
12307fc2 DW |
543 | rule_bins: FilterRule, |
544 | rule_tsts: FilterRule, | |
545 | rule_exms: FilterRule, | |
546 | rule_bens: FilterRule, | |
547 | ) -> CompileFilter { | |
aef99e0e | 548 | if rule_lib == LibRule::True |
dae87a26 E |
549 | || rule_bins.is_specific() |
550 | || rule_tsts.is_specific() | |
551 | || rule_exms.is_specific() | |
552 | || rule_bens.is_specific() | |
1e682848 | 553 | { |
7a1d8d94 | 554 | CompileFilter::Only { |
b9497ab2 | 555 | all_targets: false, |
aef99e0e | 556 | lib: rule_lib, |
1e682848 AC |
557 | bins: rule_bins, |
558 | examples: rule_exms, | |
559 | benches: rule_bens, | |
2a82378a | 560 | tests: rule_tsts, |
7a1d8d94 AC |
561 | } |
562 | } else { | |
6344db05 | 563 | CompileFilter::Default { |
25e50b58 JB |
564 | required_features_filterable: true, |
565 | } | |
7a1d8d94 AC |
566 | } |
567 | } | |
568 | ||
5a59b809 EH |
569 | pub fn new_all_targets() -> CompileFilter { |
570 | CompileFilter::Only { | |
571 | all_targets: true, | |
572 | lib: LibRule::Default, | |
573 | bins: FilterRule::All, | |
574 | examples: FilterRule::All, | |
575 | benches: FilterRule::All, | |
576 | tests: FilterRule::All, | |
577 | } | |
578 | } | |
579 | ||
89d5161d XL |
580 | pub fn need_dev_deps(&self, mode: CompileMode) -> bool { |
581 | match mode { | |
582 | CompileMode::Test | CompileMode::Doctest | CompileMode::Bench => true, | |
583 | CompileMode::Build | CompileMode::Doc { .. } | CompileMode::Check { .. } => match *self | |
584 | { | |
585 | CompileFilter::Default { .. } => false, | |
586 | CompileFilter::Only { | |
587 | ref examples, | |
588 | ref tests, | |
589 | ref benches, | |
590 | .. | |
591 | } => examples.is_specific() || tests.is_specific() || benches.is_specific(), | |
592 | }, | |
575d6e81 | 593 | CompileMode::RunCustomBuild => panic!("Invalid mode"), |
7de30dd2 XL |
594 | } |
595 | } | |
596 | ||
ce26ddfd | 597 | // this selects targets for "cargo run". for logic to select targets for |
771fec3c | 598 | // other subcommands, see generate_targets and filter_default_targets |
ce26ddfd | 599 | pub fn target_run(&self, target: &Target) -> bool { |
9e779198 | 600 | match *self { |
70170d1b | 601 | CompileFilter::Default { .. } => true, |
1e682848 | 602 | CompileFilter::Only { |
aef99e0e | 603 | ref lib, |
1e682848 AC |
604 | ref bins, |
605 | ref examples, | |
606 | ref tests, | |
607 | ref benches, | |
608 | .. | |
609 | } => { | |
2a82378a | 610 | let rule = match *target.kind() { |
9e779198 AC |
611 | TargetKind::Bin => bins, |
612 | TargetKind::Test => tests, | |
613 | TargetKind::Bench => benches, | |
1e682848 | 614 | TargetKind::ExampleBin | TargetKind::ExampleLib(..) => examples, |
f16efff1 AC |
615 | TargetKind::Lib(..) => { |
616 | return match *lib { | |
617 | LibRule::True => true, | |
618 | LibRule::Default => true, | |
619 | LibRule::False => false, | |
620 | }; | |
621 | } | |
9e779198 AC |
622 | TargetKind::CustomBuild => return false, |
623 | }; | |
2a82378a | 624 | rule.matches(target) |
9e779198 AC |
625 | } |
626 | } | |
627 | } | |
c98b8c4c BW |
628 | |
629 | pub fn is_specific(&self) -> bool { | |
630 | match *self { | |
6344db05 | 631 | CompileFilter::Default { .. } => false, |
c98b8c4c BW |
632 | CompileFilter::Only { .. } => true, |
633 | } | |
634 | } | |
9e779198 AC |
635 | } |
636 | ||
3a1cad6f EH |
637 | /// A proposed target. |
638 | /// | |
f7c91ba6 | 639 | /// Proposed targets are later filtered into actual `Unit`s based on whether or |
3a1cad6f EH |
640 | /// not the target requires its features to be present. |
641 | #[derive(Debug)] | |
642 | struct Proposal<'a> { | |
643 | pkg: &'a Package, | |
644 | target: &'a Target, | |
645 | /// Indicates whether or not all required features *must* be present. If | |
646 | /// false, and the features are not available, then it will be silently | |
647 | /// skipped. Generally, targets specified by name (`--bin foo`) are | |
648 | /// required, all others can be silently skipped if features are missing. | |
649 | requires_features: bool, | |
650 | mode: CompileMode, | |
651 | } | |
652 | ||
575d6e81 | 653 | /// Generates all the base targets for the packages the user has requested to |
f7c91ba6 | 654 | /// compile. Dependencies for these targets are computed later in `unit_dependencies`. |
575d6e81 | 655 | fn generate_targets<'a>( |
b8b7faee | 656 | ws: &Workspace<'_>, |
575d6e81 EH |
657 | packages: &[&'a Package], |
658 | filter: &CompileFilter, | |
ef425b77 | 659 | default_arch_kind: CompileKind, |
1f14fa31 | 660 | resolve: &'a Resolve, |
e4544466 | 661 | bcx: &BuildContext<'a, '_>, |
575d6e81 | 662 | ) -> CargoResult<Vec<Unit<'a>>> { |
f7c91ba6 | 663 | // Helper for creating a `Unit` struct. |
a4947c2b | 664 | let new_unit = |pkg: &'a Package, target: &'a Target, target_mode: CompileMode| { |
f37f3aea | 665 | let unit_for = if target_mode.is_any_test() { |
f7c91ba6 | 666 | // NOTE: the `UnitFor` here is subtle. If you have a profile |
a4947c2b | 667 | // with `panic` set, the `panic` flag is cleared for |
f7c91ba6 | 668 | // tests/benchmarks and their dependencies. If this |
86489946 | 669 | // was `normal`, then the lib would get compiled three |
a4947c2b | 670 | // times (once with panic, once without, and once with |
f7c91ba6 | 671 | // `--test`). |
a4947c2b | 672 | // |
f7c91ba6 | 673 | // This would cause a problem for doc tests, which would fail |
a4947c2b EH |
674 | // because `rustdoc` would attempt to link with both libraries |
675 | // at the same time. Also, it's probably not important (or | |
676 | // even desirable?) for rustdoc to link with a lib with | |
677 | // `panic` set. | |
678 | // | |
679 | // As a consequence, Examples and Binaries get compiled | |
f7c91ba6 | 680 | // without `panic` set. This probably isn't a bad deal. |
a4947c2b EH |
681 | // |
682 | // Forcing the lib to be compiled three times during `cargo | |
683 | // test` is probably also not desirable. | |
f37f3aea | 684 | UnitFor::new_test(bcx.config) |
86489946 | 685 | } else if target.for_host() { |
f7c91ba6 | 686 | // Proc macro / plugin should not have `panic` set. |
86489946 | 687 | UnitFor::new_compiler() |
a4947c2b | 688 | } else { |
86489946 | 689 | UnitFor::new_normal() |
a4947c2b | 690 | }; |
86489946 EH |
691 | // Custom build units are added in `build_unit_dependencies`. |
692 | assert!(!target.is_custom_build()); | |
a4947c2b EH |
693 | let target_mode = match target_mode { |
694 | CompileMode::Test => { | |
dffc5bae | 695 | if target.is_example() && !filter.is_specific() && !target.tested() { |
a4947c2b EH |
696 | // Examples are included as regular binaries to verify |
697 | // that they compile. | |
698 | CompileMode::Build | |
699 | } else { | |
700 | CompileMode::Test | |
2a82378a BW |
701 | } |
702 | } | |
a4947c2b EH |
703 | CompileMode::Build => match *target.kind() { |
704 | TargetKind::Test => CompileMode::Test, | |
705 | TargetKind::Bench => CompileMode::Bench, | |
706 | _ => CompileMode::Build, | |
707 | }, | |
f7c91ba6 | 708 | // `CompileMode::Bench` is only used to inform `filter_default_targets` |
739c272f EH |
709 | // which command is being used (`cargo bench`). Afterwards, tests |
710 | // and benches are treated identically. Switching the mode allows | |
f7c91ba6 | 711 | // de-duplication of units that are essentially identical. For |
739c272f EH |
712 | // example, `cargo build --all-targets --release` creates the units |
713 | // (lib profile:bench, mode:test) and (lib profile:bench, mode:bench) | |
f7c91ba6 | 714 | // and since these are the same, we want them to be de-duplicated in |
739c272f EH |
715 | // `unit_dependencies`. |
716 | CompileMode::Bench => CompileMode::Test, | |
a4947c2b | 717 | _ => target_mode, |
575d6e81 | 718 | }; |
ef425b77 | 719 | let kind = default_arch_kind.for_target(target); |
77ee608d EH |
720 | let profile = |
721 | bcx.profiles | |
722 | .get_profile(pkg.package_id(), ws.is_member(pkg), unit_for, target_mode); | |
1f14fa31 | 723 | let features = resolve.features_sorted(pkg.package_id()); |
e9dd3066 EH |
724 | bcx.units.intern( |
725 | pkg, | |
726 | target, | |
727 | profile, | |
728 | kind, | |
729 | target_mode, | |
730 | features, | |
731 | /*is_std*/ false, | |
732 | ) | |
a4947c2b | 733 | }; |
575d6e81 | 734 | |
3a1cad6f | 735 | // Create a list of proposed targets. |
b8b7faee | 736 | let mut proposals: Vec<Proposal<'_>> = Vec::new(); |
771fec3c EH |
737 | |
738 | match *filter { | |
739 | CompileFilter::Default { | |
740 | required_features_filterable, | |
741 | } => { | |
742 | for pkg in packages { | |
e4544466 | 743 | let default = filter_default_targets(pkg.targets(), bcx.build_config.mode); |
3a1cad6f EH |
744 | proposals.extend(default.into_iter().map(|target| Proposal { |
745 | pkg, | |
746 | target, | |
747 | requires_features: !required_features_filterable, | |
e4544466 | 748 | mode: bcx.build_config.mode, |
771fec3c | 749 | })); |
e4544466 | 750 | if bcx.build_config.mode == CompileMode::Test { |
dd6c6102 EH |
751 | if let Some(t) = pkg |
752 | .targets() | |
753 | .iter() | |
754 | .find(|t| t.is_lib() && t.doctested() && t.doctestable()) | |
755 | { | |
3a1cad6f EH |
756 | proposals.push(Proposal { |
757 | pkg, | |
758 | target: t, | |
759 | requires_features: false, | |
760 | mode: CompileMode::Doctest, | |
761 | }); | |
575d6e81 | 762 | } |
2a82378a BW |
763 | } |
764 | } | |
771fec3c EH |
765 | } |
766 | CompileFilter::Only { | |
767 | all_targets, | |
aef99e0e | 768 | ref lib, |
771fec3c EH |
769 | ref bins, |
770 | ref examples, | |
771 | ref tests, | |
772 | ref benches, | |
773 | } => { | |
aef99e0e | 774 | if *lib != LibRule::False { |
771fec3c | 775 | let mut libs = Vec::new(); |
63a9c7aa | 776 | for proposal in |
777 | filter_targets(packages, Target::is_lib, false, bcx.build_config.mode) | |
778 | { | |
df9ca871 | 779 | let Proposal { target, pkg, .. } = proposal; |
935adb31 | 780 | if bcx.build_config.mode.is_doc_test() && !target.doctestable() { |
df9ca871 DW |
781 | ws.config().shell().warn(format!( |
782 | "doc tests are not supported for crate type(s) `{}` in package `{}`", | |
783 | target.rustc_crate_types().join(", "), | |
784 | pkg.name() | |
785 | ))?; | |
786 | } else { | |
787 | libs.push(proposal) | |
575d6e81 EH |
788 | } |
789 | } | |
aef99e0e | 790 | if !all_targets && libs.is_empty() && *lib == LibRule::True { |
771fec3c EH |
791 | let names = packages.iter().map(|pkg| pkg.name()).collect::<Vec<_>>(); |
792 | if names.len() == 1 { | |
3a18c89a | 793 | anyhow::bail!("no library targets found in package `{}`", names[0]); |
771fec3c | 794 | } else { |
3a18c89a | 795 | anyhow::bail!("no library targets found in packages: {}", names.join(", ")); |
771fec3c EH |
796 | } |
797 | } | |
798 | proposals.extend(libs); | |
575d6e81 | 799 | } |
3a1cad6f | 800 | |
f7c91ba6 | 801 | // If `--tests` was specified, add all targets that would be |
771fec3c | 802 | // generated by `cargo test`. |
df9ca871 | 803 | let test_filter = match tests { |
771fec3c EH |
804 | FilterRule::All => Target::tested, |
805 | FilterRule::Just(_) => Target::is_test, | |
806 | }; | |
e4544466 | 807 | let test_mode = match bcx.build_config.mode { |
771fec3c EH |
808 | CompileMode::Build => CompileMode::Test, |
809 | CompileMode::Check { .. } => CompileMode::Check { test: true }, | |
e4544466 | 810 | _ => bcx.build_config.mode, |
771fec3c | 811 | }; |
f7c91ba6 | 812 | // If `--benches` was specified, add all targets that would be |
771fec3c | 813 | // generated by `cargo bench`. |
df9ca871 | 814 | let bench_filter = match benches { |
771fec3c EH |
815 | FilterRule::All => Target::benched, |
816 | FilterRule::Just(_) => Target::is_bench, | |
817 | }; | |
e4544466 | 818 | let bench_mode = match bcx.build_config.mode { |
771fec3c EH |
819 | CompileMode::Build => CompileMode::Bench, |
820 | CompileMode::Check { .. } => CompileMode::Check { test: true }, | |
e4544466 | 821 | _ => bcx.build_config.mode, |
771fec3c EH |
822 | }; |
823 | ||
824 | proposals.extend(list_rule_targets( | |
825 | packages, | |
826 | bins, | |
827 | "bin", | |
828 | Target::is_bin, | |
e4544466 | 829 | bcx.build_config.mode, |
771fec3c EH |
830 | )?); |
831 | proposals.extend(list_rule_targets( | |
832 | packages, | |
833 | examples, | |
834 | "example", | |
835 | Target::is_example, | |
e4544466 | 836 | bcx.build_config.mode, |
771fec3c EH |
837 | )?); |
838 | proposals.extend(list_rule_targets( | |
839 | packages, | |
840 | tests, | |
841 | "test", | |
842 | test_filter, | |
843 | test_mode, | |
844 | )?); | |
845 | proposals.extend(list_rule_targets( | |
846 | packages, | |
847 | benches, | |
848 | "bench", | |
849 | bench_filter, | |
850 | bench_mode, | |
851 | )?); | |
2a82378a | 852 | } |
771fec3c | 853 | } |
2a82378a | 854 | |
771fec3c EH |
855 | // Only include targets that are libraries or have all required |
856 | // features available. | |
857 | let mut features_map = HashMap::new(); | |
3a1cad6f | 858 | let mut units = HashSet::new(); |
dae87a26 E |
859 | for Proposal { |
860 | pkg, | |
861 | target, | |
862 | requires_features, | |
863 | mode, | |
864 | } in proposals | |
865 | { | |
771fec3c EH |
866 | let unavailable_features = match target.required_features() { |
867 | Some(rf) => { | |
868 | let features = features_map | |
869 | .entry(pkg) | |
870 | .or_insert_with(|| resolve_all_features(resolve, pkg.package_id())); | |
871 | rf.iter().filter(|f| !features.contains(*f)).collect() | |
2a82378a | 872 | } |
771fec3c EH |
873 | None => Vec::new(), |
874 | }; | |
875 | if target.is_lib() || unavailable_features.is_empty() { | |
876 | let unit = new_unit(pkg, target, mode); | |
3a1cad6f EH |
877 | units.insert(unit); |
878 | } else if requires_features { | |
771fec3c EH |
879 | let required_features = target.required_features().unwrap(); |
880 | let quoted_required_features: Vec<String> = required_features | |
881 | .iter() | |
882 | .map(|s| format!("`{}`", s)) | |
883 | .collect(); | |
3a18c89a | 884 | anyhow::bail!( |
771fec3c | 885 | "target `{}` in package `{}` requires the features: {}\n\ |
f7c91ba6 | 886 | Consider enabling them by passing, e.g., `--features=\"{}\"`", |
771fec3c EH |
887 | target.name(), |
888 | pkg.name(), | |
889 | quoted_required_features.join(", "), | |
890 | required_features.join(" ") | |
891 | ); | |
2a82378a | 892 | } |
771fec3c | 893 | // else, silently skip target. |
2a82378a | 894 | } |
3a1cad6f | 895 | Ok(units.into_iter().collect()) |
2a82378a BW |
896 | } |
897 | ||
575d6e81 EH |
898 | fn resolve_all_features( |
899 | resolve_with_overrides: &Resolve, | |
dae87a26 | 900 | package_id: PackageId, |
575d6e81 EH |
901 | ) -> HashSet<String> { |
902 | let mut features = resolve_with_overrides.features(package_id).clone(); | |
903 | ||
904 | // Include features enabled for use by dependencies so targets can also use them with the | |
905 | // required-features field when deciding whether to be built or skipped. | |
906 | for (dep, _) in resolve_with_overrides.deps(package_id) { | |
907 | for feature in resolve_with_overrides.features(dep) { | |
908 | features.insert(dep.name().to_string() + "/" + feature); | |
909 | } | |
910 | } | |
911 | ||
912 | features | |
913 | } | |
914 | ||
915 | /// Given a list of all targets for a package, filters out only the targets | |
916 | /// that are automatically included when the user doesn't specify any targets. | |
771fec3c | 917 | fn filter_default_targets(targets: &[Target], mode: CompileMode) -> Vec<&Target> { |
575d6e81 EH |
918 | match mode { |
919 | CompileMode::Bench => targets.iter().filter(|t| t.benched()).collect(), | |
a4947c2b EH |
920 | CompileMode::Test => targets |
921 | .iter() | |
922 | .filter(|t| t.tested() || t.is_example()) | |
923 | .collect(), | |
575d6e81 EH |
924 | CompileMode::Build | CompileMode::Check { .. } => targets |
925 | .iter() | |
926 | .filter(|t| t.is_bin() || t.is_lib()) | |
927 | .collect(), | |
928 | CompileMode::Doc { .. } => { | |
929 | // `doc` does lib and bins (bin with same name as lib is skipped). | |
930 | targets | |
1e682848 | 931 | .iter() |
575d6e81 EH |
932 | .filter(|t| { |
933 | t.documented() | |
934 | && (!t.is_bin() | |
935 | || !targets.iter().any(|l| l.is_lib() && l.name() == t.name())) | |
936 | }) | |
937 | .collect() | |
2a82378a | 938 | } |
00d325db | 939 | CompileMode::Doctest | CompileMode::RunCustomBuild => panic!("Invalid mode {:?}", mode), |
2a82378a | 940 | } |
2a82378a BW |
941 | } |
942 | ||
df9ca871 | 943 | /// Returns a list of proposed targets based on command-line target selection flags. |
575d6e81 | 944 | fn list_rule_targets<'a>( |
771fec3c | 945 | packages: &[&'a Package], |
575d6e81 EH |
946 | rule: &FilterRule, |
947 | target_desc: &'static str, | |
948 | is_expected_kind: fn(&Target) -> bool, | |
771fec3c | 949 | mode: CompileMode, |
3a1cad6f | 950 | ) -> CargoResult<Vec<Proposal<'a>>> { |
df9ca871 DW |
951 | let mut proposals = Vec::new(); |
952 | match rule { | |
771fec3c | 953 | FilterRule::All => { |
df9ca871 | 954 | proposals.extend(filter_targets(packages, is_expected_kind, false, mode)) |
771fec3c | 955 | } |
df9ca871 | 956 | FilterRule::Just(names) => { |
771fec3c | 957 | for name in names { |
df9ca871 | 958 | proposals.extend(find_named_targets( |
771fec3c EH |
959 | packages, |
960 | name, | |
961 | target_desc, | |
962 | is_expected_kind, | |
963 | mode, | |
964 | )?); | |
965 | } | |
966 | } | |
575d6e81 | 967 | } |
df9ca871 | 968 | Ok(proposals) |
575d6e81 | 969 | } |
235712f5 | 970 | |
f7c91ba6 | 971 | /// Finds the targets for a specifically named target. |
771fec3c EH |
972 | fn find_named_targets<'a>( |
973 | packages: &[&'a Package], | |
575d6e81 EH |
974 | target_name: &str, |
975 | target_desc: &'static str, | |
976 | is_expected_kind: fn(&Target) -> bool, | |
771fec3c | 977 | mode: CompileMode, |
3a1cad6f | 978 | ) -> CargoResult<Vec<Proposal<'a>>> { |
df9ca871 DW |
979 | let filter = |t: &Target| t.name() == target_name && is_expected_kind(t); |
980 | let proposals = filter_targets(packages, filter, true, mode); | |
981 | if proposals.is_empty() { | |
7d7fe679 EH |
982 | let targets = packages.iter().flat_map(|pkg| { |
983 | pkg.targets() | |
984 | .iter() | |
985 | .filter(|target| is_expected_kind(target)) | |
986 | }); | |
987 | let suggestion = closest_msg(target_name, targets, |t| t.name()); | |
3a18c89a | 988 | anyhow::bail!( |
7d7fe679 EH |
989 | "no {} target named `{}`{}", |
990 | target_desc, | |
991 | target_name, | |
992 | suggestion | |
993 | ); | |
771fec3c | 994 | } |
df9ca871 DW |
995 | Ok(proposals) |
996 | } | |
997 | ||
998 | fn filter_targets<'a>( | |
999 | packages: &[&'a Package], | |
1000 | predicate: impl Fn(&Target) -> bool, | |
1001 | requires_features: bool, | |
1002 | mode: CompileMode, | |
1003 | ) -> Vec<Proposal<'a>> { | |
1004 | let mut proposals = Vec::new(); | |
1005 | for pkg in packages { | |
1006 | for target in pkg.targets().iter().filter(|t| predicate(t)) { | |
1007 | proposals.push(Proposal { | |
1008 | pkg, | |
1009 | target, | |
1010 | requires_features, | |
1011 | mode, | |
1012 | }); | |
1013 | } | |
1014 | } | |
1015 | proposals | |
9e779198 | 1016 | } |
70bea01b AC |
1017 | |
1018 | /// When using `-Zbuild-std` we're building the standard library, but a | |
1019 | /// technical detail of the standard library right now is that it builds itself | |
1020 | /// as both an `rlib` and a `dylib`. We don't actually want to really publicize | |
1021 | /// the `dylib` and in general it's a pain to work with, so when building libstd | |
1022 | /// we want to remove the `dylib` crate type. | |
1023 | /// | |
1024 | /// Cargo doesn't have a fantastic way of doing that right now, so let's hack | |
1025 | /// around it a bit and (ab)use the fact that we have mutable access to | |
1026 | /// `PackageSet` here to rewrite downloaded packages. We iterate over all `path` | |
1027 | /// packages (which should download immediately and not actually cause blocking | |
1028 | /// here) and edit their manifests to only list one `LibKind` for an `Rlib`. | |
1029 | fn remove_dylib_crate_type(set: &mut PackageSet<'_>) -> CargoResult<()> { | |
1030 | let ids = set | |
1031 | .package_ids() | |
1032 | .filter(|p| p.source_id().is_path()) | |
1033 | .collect::<Vec<_>>(); | |
1034 | set.get_many(ids.iter().cloned())?; | |
1035 | ||
1036 | for id in ids { | |
1037 | let pkg = set.lookup_mut(id).expect("should be downloaded now"); | |
1038 | ||
1039 | for target in pkg.manifest_mut().targets_mut() { | |
1040 | if let TargetKind::Lib(crate_types) = target.kind_mut() { | |
1041 | crate_types.truncate(0); | |
1042 | crate_types.push(LibKind::Rlib); | |
1043 | } | |
1044 | } | |
1045 | } | |
1046 | ||
1047 | Ok(()) | |
1048 | } |