]> git.proxmox.com Git - cargo.git/blob - src/cargo/core/compiler/unit_dependencies.rs
Remove redundant check for Kind::Target.
[cargo.git] / src / cargo / core / compiler / unit_dependencies.rs
1 //! Constructs the dependency graph for compilation.
2 //!
3 //! Rust code is typically organized as a set of Cargo packages. The
4 //! dependencies between the packages themselves are stored in the
5 //! `Resolve` struct. However, we can't use that information as is for
6 //! compilation! A package typically contains several targets, or crates,
7 //! and these targets has inter-dependencies. For example, you need to
8 //! compile the `lib` target before the `bin` one, and you need to compile
9 //! `build.rs` before either of those.
10 //!
11 //! So, we need to lower the `Resolve`, which specifies dependencies between
12 //! *packages*, to a graph of dependencies between their *targets*, and this
13 //! is exactly what this module is doing! Well, almost exactly: another
14 //! complication is that we might want to compile the same target several times
15 //! (for example, with and without tests), so we actually build a dependency
16 //! graph of `Unit`s, which capture these properties.
17
18 use crate::core::compiler::Unit;
19 use crate::core::compiler::{BuildContext, CompileMode, Kind};
20 use crate::core::dependency::Kind as DepKind;
21 use crate::core::package::Downloads;
22 use crate::core::profiles::{Profile, UnitFor};
23 use crate::core::resolver::Resolve;
24 use crate::core::{InternedString, Package, PackageId, Target};
25 use crate::CargoResult;
26 use log::trace;
27 use std::collections::{HashMap, HashSet};
28
29 /// The dependency graph of Units.
30 pub type UnitGraph<'a> = HashMap<Unit<'a>, Vec<UnitDep<'a>>>;
31
32 /// A unit dependency.
33 #[derive(Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord)]
34 pub struct UnitDep<'a> {
35 /// The dependency unit.
36 pub unit: Unit<'a>,
37 /// The purpose of this dependency (a dependency for a test, or a build
38 /// script, etc.).
39 pub unit_for: UnitFor,
40 /// The name the parent uses to refer to this dependency.
41 pub extern_crate_name: InternedString,
42 /// Whether or not this is a public dependency.
43 pub public: bool,
44 }
45
46 /// Collection of stuff used while creating the `UnitGraph`.
47 struct State<'a, 'cfg> {
48 bcx: &'a BuildContext<'a, 'cfg>,
49 waiting_on_download: HashSet<PackageId>,
50 downloads: Downloads<'a, 'cfg>,
51 unit_dependencies: UnitGraph<'a>,
52 package_cache: HashMap<PackageId, &'a Package>,
53 usr_resolve: &'a Resolve,
54 std_resolve: Option<&'a Resolve>,
55 /// This flag is `true` while generating the dependencies for the standard
56 /// library.
57 is_std: bool,
58 }
59
60 pub fn build_unit_dependencies<'a, 'cfg>(
61 bcx: &'a BuildContext<'a, 'cfg>,
62 resolve: &'a Resolve,
63 std_resolve: Option<&'a Resolve>,
64 roots: &[Unit<'a>],
65 std_roots: &[Unit<'a>],
66 ) -> CargoResult<UnitGraph<'a>> {
67 let mut state = State {
68 bcx,
69 downloads: bcx.packages.enable_download()?,
70 waiting_on_download: HashSet::new(),
71 unit_dependencies: HashMap::new(),
72 package_cache: HashMap::new(),
73 usr_resolve: resolve,
74 std_resolve,
75 is_std: false,
76 };
77
78 let std_unit_deps = calc_deps_of_std(&mut state, std_roots)?;
79 let libtest_unit_deps = calc_deps_of_libtest(&mut state, std_roots, roots)?;
80
81 deps_of_roots(roots, &mut state)?;
82 super::links::validate_links(state.resolve(), &state.unit_dependencies)?;
83 // Hopefully there aren't any links conflicts with the standard library?
84
85 if let Some(mut std_unit_deps) = std_unit_deps {
86 if let Some(libtest_unit_deps) = libtest_unit_deps {
87 attach_std_test(&mut state, libtest_unit_deps, &std_unit_deps);
88 }
89 fixup_proc_macro(&mut std_unit_deps);
90 attach_std_deps(&mut state, std_roots, std_unit_deps);
91 }
92
93 connect_run_custom_build_deps(&mut state.unit_dependencies);
94
95 // Dependencies are used in tons of places throughout the backend, many of
96 // which affect the determinism of the build itself. As a result be sure
97 // that dependency lists are always sorted to ensure we've always got a
98 // deterministic output.
99 for list in state.unit_dependencies.values_mut() {
100 list.sort();
101 }
102 trace!("ALL UNIT DEPENDENCIES {:#?}", state.unit_dependencies);
103
104 Ok(state.unit_dependencies)
105 }
106
107 /// Compute all the dependencies for the standard library.
108 fn calc_deps_of_std<'a, 'cfg>(
109 mut state: &mut State<'a, 'cfg>,
110 std_roots: &[Unit<'a>],
111 ) -> CargoResult<Option<UnitGraph<'a>>> {
112 if std_roots.is_empty() {
113 return Ok(None);
114 }
115 // Compute dependencies for the standard library.
116 state.is_std = true;
117 deps_of_roots(std_roots, &mut state)?;
118 state.is_std = false;
119 Ok(Some(std::mem::replace(
120 &mut state.unit_dependencies,
121 HashMap::new(),
122 )))
123 }
124
125 /// Compute all the dependencies for libtest.
126 /// Returns None if libtest is not needed.
127 fn calc_deps_of_libtest<'a, 'cfg>(
128 mut state: &mut State<'a, 'cfg>,
129 std_roots: &[Unit<'a>],
130 roots: &[Unit<'a>],
131 ) -> CargoResult<Option<UnitGraph<'a>>> {
132 // Conditionally include libtest.
133 if std_roots.is_empty()
134 || !roots
135 .iter()
136 .any(|unit| unit.mode.is_rustc_test() && unit.target.harness())
137 {
138 return Ok(None);
139 }
140 state.is_std = true;
141 let test_id = state.resolve().query("test")?;
142 let test_pkg = state.get(test_id)?.expect("test doesn't need downloading");
143 let test_target = test_pkg
144 .targets()
145 .iter()
146 .find(|t| t.is_lib())
147 .expect("test has a lib");
148 let test_unit = new_unit(
149 state,
150 test_pkg,
151 test_target,
152 UnitFor::new_normal(),
153 Kind::Target,
154 CompileMode::Build,
155 );
156 let res = calc_deps_of_std(state, &[test_unit])?;
157 state.is_std = false;
158 Ok(res)
159 }
160
161 /// `proc_macro` has an implicit dependency on `std`, add it.
162 fn fixup_proc_macro<'a>(std_unit_deps: &mut UnitGraph<'a>) {
163 // Synthesize a dependency from proc_macro -> std.
164 //
165 // This is a gross hack. This wouldn't be necessary with `--sysroot`. See
166 // also libtest below.
167 if let Some(std) = std_unit_deps
168 .keys()
169 .find(|unit| unit.pkg.name().as_str() == "std" && unit.target.is_lib())
170 .cloned()
171 {
172 for (unit, deps) in std_unit_deps.iter_mut() {
173 if unit.pkg.name().as_str() == "proc_macro" {
174 deps.push(UnitDep {
175 unit: std,
176 unit_for: UnitFor::new_normal(),
177 extern_crate_name: InternedString::new("std"),
178 public: true,
179 });
180 }
181 }
182 }
183 }
184
185 /// Add libtest as a dependency of any test unit that needs it.
186 fn attach_std_test<'a, 'cfg>(
187 state: &mut State<'a, 'cfg>,
188 mut libtest_unit_deps: UnitGraph<'a>,
189 std_unit_deps: &UnitGraph<'a>,
190 ) {
191 // Attach libtest to any test unit.
192 let (test_unit, test_deps) = libtest_unit_deps
193 .iter_mut()
194 .find(|(k, _v)| k.pkg.name().as_str() == "test" && k.target.is_lib())
195 .expect("test in deps");
196 for (unit, deps) in state.unit_dependencies.iter_mut() {
197 if unit.mode.is_rustc_test() && unit.target.harness() {
198 // `public` here will need to be driven by toml declaration.
199 deps.push(UnitDep {
200 unit: *test_unit,
201 unit_for: UnitFor::new_normal(),
202 extern_crate_name: test_unit.pkg.name(),
203 public: false,
204 });
205 }
206 }
207
208 // Synthesize a dependency from libtest -> libc.
209 //
210 // This is a gross hack. In theory, libtest should explicitly list this,
211 // but presumably it would cause libc to be built again when it just uses
212 // the version from sysroot. This won't be necessary if Cargo uses
213 // `--sysroot`.
214 let libc_unit = std_unit_deps
215 .keys()
216 .find(|unit| unit.pkg.name().as_str() == "libc" && unit.target.is_lib())
217 .expect("libc in deps");
218 let libc_dep = UnitDep {
219 unit: *libc_unit,
220 unit_for: UnitFor::new_normal(),
221 extern_crate_name: InternedString::new(&libc_unit.target.crate_name()),
222 public: false,
223 };
224 test_deps.push(libc_dep);
225
226 // And also include the dependencies of libtest itself.
227 for (unit, deps) in libtest_unit_deps.into_iter() {
228 if let Some(other_unit) = state.unit_dependencies.insert(unit, deps) {
229 panic!(
230 "libtest unit collision with existing unit: {:?}",
231 other_unit
232 );
233 }
234 }
235 }
236
237 /// Add the standard library units to the `unit_dependencies`.
238 fn attach_std_deps<'a, 'cfg>(
239 state: &mut State<'a, 'cfg>,
240 std_roots: &[Unit<'a>],
241 std_unit_deps: UnitGraph<'a>,
242 ) {
243 // Attach the standard library as a dependency of every target unit.
244 for (unit, deps) in state.unit_dependencies.iter_mut() {
245 if unit.kind == Kind::Target && !unit.mode.is_run_custom_build() {
246 deps.extend(std_roots.iter().map(|unit| UnitDep {
247 unit: *unit,
248 unit_for: UnitFor::new_normal(),
249 extern_crate_name: unit.pkg.name(),
250 // TODO: Does this `public` make sense?
251 public: true,
252 }));
253 }
254 }
255 // And also include the dependencies of the standard library itself.
256 for (unit, deps) in std_unit_deps.into_iter() {
257 if let Some(other_unit) = state.unit_dependencies.insert(unit, deps) {
258 panic!("std unit collision with existing unit: {:?}", other_unit);
259 }
260 }
261 }
262
263 /// Compute all the dependencies of the given root units.
264 /// The result is stored in state.unit_dependencies.
265 fn deps_of_roots<'a, 'cfg>(roots: &[Unit<'a>], mut state: &mut State<'a, 'cfg>) -> CargoResult<()> {
266 // Loop because we are downloading while building the dependency graph.
267 // The partially-built unit graph is discarded through each pass of the
268 // loop because it is incomplete because not all required Packages have
269 // been downloaded.
270 loop {
271 for unit in roots.iter() {
272 state.get(unit.pkg.package_id())?;
273
274 // Dependencies of tests/benches should not have `panic` set.
275 // We check the global test mode to see if we are running in `cargo
276 // test` in which case we ensure all dependencies have `panic`
277 // cleared, and avoid building the lib thrice (once with `panic`, once
278 // without, once for `--test`). In particular, the lib included for
279 // Doc tests and examples are `Build` mode here.
280 let unit_for = if unit.mode.is_any_test() || state.bcx.build_config.test() {
281 UnitFor::new_test()
282 } else if unit.target.is_custom_build() {
283 // This normally doesn't happen, except `clean` aggressively
284 // generates all units.
285 UnitFor::new_build()
286 } else if unit.target.for_host() {
287 // Proc macro / plugin should never have panic set.
288 UnitFor::new_compiler()
289 } else {
290 UnitFor::new_normal()
291 };
292 deps_of(unit, &mut state, unit_for)?;
293 }
294
295 if !state.waiting_on_download.is_empty() {
296 state.finish_some_downloads()?;
297 state.unit_dependencies.clear();
298 } else {
299 break;
300 }
301 }
302 Ok(())
303 }
304
305 /// Compute the dependencies of a single unit.
306 fn deps_of<'a, 'cfg>(
307 unit: &Unit<'a>,
308 state: &mut State<'a, 'cfg>,
309 unit_for: UnitFor,
310 ) -> CargoResult<()> {
311 // Currently the `unit_dependencies` map does not include `unit_for`. This should
312 // be safe for now. `TestDependency` only exists to clear the `panic`
313 // flag, and you'll never ask for a `unit` with `panic` set as a
314 // `TestDependency`. `CustomBuild` should also be fine since if the
315 // requested unit's settings are the same as `Any`, `CustomBuild` can't
316 // affect anything else in the hierarchy.
317 if !state.unit_dependencies.contains_key(unit) {
318 let unit_deps = compute_deps(unit, state, unit_for)?;
319 state.unit_dependencies.insert(*unit, unit_deps.clone());
320 for unit_dep in unit_deps {
321 deps_of(&unit_dep.unit, state, unit_dep.unit_for)?;
322 }
323 }
324 Ok(())
325 }
326
327 /// For a package, returns all targets that are registered as dependencies
328 /// for that package.
329 /// This returns a `Vec` of `(Unit, UnitFor)` pairs. The `UnitFor`
330 /// is the profile type that should be used for dependencies of the unit.
331 fn compute_deps<'a, 'cfg>(
332 unit: &Unit<'a>,
333 state: &mut State<'a, 'cfg>,
334 unit_for: UnitFor,
335 ) -> CargoResult<Vec<UnitDep<'a>>> {
336 if unit.mode.is_run_custom_build() {
337 return compute_deps_custom_build(unit, state);
338 } else if unit.mode.is_doc() {
339 // Note: this does not include doc test.
340 return compute_deps_doc(unit, state);
341 }
342
343 let bcx = state.bcx;
344 let id = unit.pkg.package_id();
345 let deps = state.resolve().deps(id).filter(|&(_id, deps)| {
346 assert!(!deps.is_empty());
347 deps.iter().any(|dep| {
348 // If this target is a build command, then we only want build
349 // dependencies, otherwise we want everything *other than* build
350 // dependencies.
351 if unit.target.is_custom_build() != dep.is_build() {
352 return false;
353 }
354
355 // If this dependency is **not** a transitive dependency, then it
356 // only applies to test/example targets.
357 if !dep.is_transitive()
358 && !unit.target.is_test()
359 && !unit.target.is_example()
360 && !unit.mode.is_any_test()
361 {
362 return false;
363 }
364
365 // If this dependency is only available for certain platforms,
366 // make sure we're only enabling it for that platform.
367 if !bcx.dep_platform_activated(dep, unit.kind) {
368 return false;
369 }
370
371 // If we've gotten past all that, then this dependency is
372 // actually used!
373 true
374 })
375 });
376
377 let mut ret = Vec::new();
378 for (id, _) in deps {
379 let pkg = match state.get(id)? {
380 Some(pkg) => pkg,
381 None => continue,
382 };
383 let lib = match pkg.targets().iter().find(|t| t.is_lib()) {
384 Some(t) => t,
385 None => continue,
386 };
387 let mode = check_or_build_mode(unit.mode, lib);
388 let dep_unit_for = unit_for.with_for_host(lib.for_host());
389
390 if bcx.config.cli_unstable().dual_proc_macros
391 && lib.proc_macro()
392 && unit.kind == Kind::Target
393 {
394 let unit_dep = new_unit_dep(state, unit, pkg, lib, dep_unit_for, Kind::Target, mode)?;
395 ret.push(unit_dep);
396 let unit_dep = new_unit_dep(state, unit, pkg, lib, dep_unit_for, Kind::Host, mode)?;
397 ret.push(unit_dep);
398 } else {
399 let unit_dep = new_unit_dep(
400 state,
401 unit,
402 pkg,
403 lib,
404 dep_unit_for,
405 unit.kind.for_target(lib),
406 mode,
407 )?;
408 ret.push(unit_dep);
409 }
410 }
411
412 // If this target is a build script, then what we've collected so far is
413 // all we need. If this isn't a build script, then it depends on the
414 // build script if there is one.
415 if unit.target.is_custom_build() {
416 return Ok(ret);
417 }
418 ret.extend(dep_build_script(unit, state)?);
419
420 // If this target is a binary, test, example, etc, then it depends on
421 // the library of the same package. The call to `resolve.deps` above
422 // didn't include `pkg` in the return values, so we need to special case
423 // it here and see if we need to push `(pkg, pkg_lib_target)`.
424 if unit.target.is_lib() && unit.mode != CompileMode::Doctest {
425 return Ok(ret);
426 }
427 ret.extend(maybe_lib(unit, state, unit_for)?);
428
429 // If any integration tests/benches are being run, make sure that
430 // binaries are built as well.
431 if !unit.mode.is_check()
432 && unit.mode.is_any_test()
433 && (unit.target.is_test() || unit.target.is_bench())
434 {
435 ret.extend(
436 unit.pkg
437 .targets()
438 .iter()
439 .filter(|t| {
440 let no_required_features = Vec::new();
441
442 t.is_bin() &&
443 // Skip binaries with required features that have not been selected.
444 t.required_features().unwrap_or(&no_required_features).iter().all(|f| {
445 unit.features.contains(&f.as_str())
446 })
447 })
448 .map(|t| {
449 new_unit_dep(
450 state,
451 unit,
452 unit.pkg,
453 t,
454 UnitFor::new_normal(),
455 unit.kind.for_target(t),
456 CompileMode::Build,
457 )
458 })
459 .collect::<CargoResult<Vec<UnitDep<'a>>>>()?,
460 );
461 }
462
463 Ok(ret)
464 }
465
466 /// Returns the dependencies needed to run a build script.
467 ///
468 /// The `unit` provided must represent an execution of a build script, and
469 /// the returned set of units must all be run before `unit` is run.
470 fn compute_deps_custom_build<'a, 'cfg>(
471 unit: &Unit<'a>,
472 state: &mut State<'a, 'cfg>,
473 ) -> CargoResult<Vec<UnitDep<'a>>> {
474 if let Some(links) = unit.pkg.manifest().links() {
475 if state.bcx.script_override(links, unit.kind).is_some() {
476 // Overridden build scripts don't have any dependencies.
477 return Ok(Vec::new());
478 }
479 }
480 // When not overridden, then the dependencies to run a build script are:
481 //
482 // 1. Compiling the build script itself.
483 // 2. For each immediate dependency of our package which has a `links`
484 // key, the execution of that build script.
485 //
486 // We don't have a great way of handling (2) here right now so this is
487 // deferred until after the graph of all unit dependencies has been
488 // constructed.
489 let unit_dep = new_unit_dep(
490 state,
491 unit,
492 unit.pkg,
493 unit.target,
494 // All dependencies of this unit should use profiles for custom
495 // builds.
496 UnitFor::new_build(),
497 // Build scripts always compiled for the host.
498 Kind::Host,
499 CompileMode::Build,
500 )?;
501 Ok(vec![unit_dep])
502 }
503
504 /// Returns the dependencies necessary to document a package.
505 fn compute_deps_doc<'a, 'cfg>(
506 unit: &Unit<'a>,
507 state: &mut State<'a, 'cfg>,
508 ) -> CargoResult<Vec<UnitDep<'a>>> {
509 let bcx = state.bcx;
510 let deps = state
511 .resolve()
512 .deps(unit.pkg.package_id())
513 .filter(|&(_id, deps)| {
514 deps.iter().any(|dep| match dep.kind() {
515 DepKind::Normal => bcx.dep_platform_activated(dep, unit.kind),
516 _ => false,
517 })
518 });
519
520 // To document a library, we depend on dependencies actually being
521 // built. If we're documenting *all* libraries, then we also depend on
522 // the documentation of the library being built.
523 let mut ret = Vec::new();
524 for (id, _deps) in deps {
525 let dep = match state.get(id)? {
526 Some(dep) => dep,
527 None => continue,
528 };
529 let lib = match dep.targets().iter().find(|t| t.is_lib()) {
530 Some(lib) => lib,
531 None => continue,
532 };
533 // Rustdoc only needs rmeta files for regular dependencies.
534 // However, for plugins/proc macros, deps should be built like normal.
535 let mode = check_or_build_mode(unit.mode, lib);
536 let dep_unit_for = UnitFor::new_normal().with_for_host(lib.for_host());
537 let lib_unit_dep = new_unit_dep(
538 state,
539 unit,
540 dep,
541 lib,
542 dep_unit_for,
543 unit.kind.for_target(lib),
544 mode,
545 )?;
546 ret.push(lib_unit_dep);
547 if let CompileMode::Doc { deps: true } = unit.mode {
548 // Document this lib as well.
549 let doc_unit_dep = new_unit_dep(
550 state,
551 unit,
552 dep,
553 lib,
554 dep_unit_for,
555 unit.kind.for_target(lib),
556 unit.mode,
557 )?;
558 ret.push(doc_unit_dep);
559 }
560 }
561
562 // Be sure to build/run the build script for documented libraries.
563 ret.extend(dep_build_script(unit, state)?);
564
565 // If we document a binary/example, we need the library available.
566 if unit.target.is_bin() || unit.target.is_example() {
567 ret.extend(maybe_lib(unit, state, UnitFor::new_normal())?);
568 }
569 Ok(ret)
570 }
571
572 fn maybe_lib<'a>(
573 unit: &Unit<'a>,
574 state: &mut State<'a, '_>,
575 unit_for: UnitFor,
576 ) -> CargoResult<Option<UnitDep<'a>>> {
577 unit.pkg
578 .targets()
579 .iter()
580 .find(|t| t.linkable())
581 .map(|t| {
582 let mode = check_or_build_mode(unit.mode, t);
583 new_unit_dep(
584 state,
585 unit,
586 unit.pkg,
587 t,
588 unit_for,
589 unit.kind.for_target(t),
590 mode,
591 )
592 })
593 .transpose()
594 }
595
596 /// If a build script is scheduled to be run for the package specified by
597 /// `unit`, this function will return the unit to run that build script.
598 ///
599 /// Overriding a build script simply means that the running of the build
600 /// script itself doesn't have any dependencies, so even in that case a unit
601 /// of work is still returned. `None` is only returned if the package has no
602 /// build script.
603 fn dep_build_script<'a>(
604 unit: &Unit<'a>,
605 state: &State<'a, '_>,
606 ) -> CargoResult<Option<UnitDep<'a>>> {
607 unit.pkg
608 .targets()
609 .iter()
610 .find(|t| t.is_custom_build())
611 .map(|t| {
612 // The profile stored in the Unit is the profile for the thing
613 // the custom build script is running for.
614 let profile = state
615 .bcx
616 .profiles
617 .get_profile_run_custom_build(&unit.profile);
618 new_unit_dep_with_profile(
619 state,
620 unit,
621 unit.pkg,
622 t,
623 UnitFor::new_build(),
624 unit.kind,
625 CompileMode::RunCustomBuild,
626 profile,
627 )
628 })
629 .transpose()
630 }
631
632 /// Choose the correct mode for dependencies.
633 fn check_or_build_mode(mode: CompileMode, target: &Target) -> CompileMode {
634 match mode {
635 CompileMode::Check { .. } | CompileMode::Doc { .. } => {
636 if target.for_host() {
637 // Plugin and proc macro targets should be compiled like
638 // normal.
639 CompileMode::Build
640 } else {
641 // Regular dependencies should not be checked with --test.
642 // Regular dependencies of doc targets should emit rmeta only.
643 CompileMode::Check { test: false }
644 }
645 }
646 _ => CompileMode::Build,
647 }
648 }
649
650 fn new_unit<'a>(
651 state: &State<'a, '_>,
652 pkg: &'a Package,
653 target: &'a Target,
654 unit_for: UnitFor,
655 kind: Kind,
656 mode: CompileMode,
657 ) -> Unit<'a> {
658 let profile = state.bcx.profiles.get_profile(
659 pkg.package_id(),
660 state.bcx.ws.is_member(pkg),
661 unit_for,
662 mode,
663 state.bcx.build_config.release,
664 );
665
666 let features = state.resolve().features_sorted(pkg.package_id());
667 state
668 .bcx
669 .units
670 .intern(pkg, target, profile, kind, mode, features)
671 }
672
673 fn new_unit_dep<'a>(
674 state: &State<'a, '_>,
675 parent: &Unit<'a>,
676 pkg: &'a Package,
677 target: &'a Target,
678 unit_for: UnitFor,
679 kind: Kind,
680 mode: CompileMode,
681 ) -> CargoResult<UnitDep<'a>> {
682 let profile = state.bcx.profiles.get_profile(
683 pkg.package_id(),
684 state.bcx.ws.is_member(pkg),
685 unit_for,
686 mode,
687 state.bcx.build_config.release,
688 );
689 new_unit_dep_with_profile(state, parent, pkg, target, unit_for, kind, mode, profile)
690 }
691
692 fn new_unit_dep_with_profile<'a>(
693 state: &State<'a, '_>,
694 parent: &Unit<'a>,
695 pkg: &'a Package,
696 target: &'a Target,
697 unit_for: UnitFor,
698 kind: Kind,
699 mode: CompileMode,
700 profile: Profile,
701 ) -> CargoResult<UnitDep<'a>> {
702 // TODO: consider making extern_crate_name return InternedString?
703 let extern_crate_name = InternedString::new(&state.resolve().extern_crate_name(
704 parent.pkg.package_id(),
705 pkg.package_id(),
706 target,
707 )?);
708 let public = state
709 .resolve()
710 .is_public_dep(parent.pkg.package_id(), pkg.package_id());
711 let features = state.resolve().features_sorted(pkg.package_id());
712 let unit = state
713 .bcx
714 .units
715 .intern(pkg, target, profile, kind, mode, features);
716 Ok(UnitDep {
717 unit,
718 unit_for,
719 extern_crate_name,
720 public,
721 })
722 }
723
724 /// Fill in missing dependencies for units of the `RunCustomBuild`
725 ///
726 /// As mentioned above in `compute_deps_custom_build` each build script
727 /// execution has two dependencies. The first is compiling the build script
728 /// itself (already added) and the second is that all crates the package of the
729 /// build script depends on with `links` keys, their build script execution. (a
730 /// bit confusing eh?)
731 ///
732 /// Here we take the entire `deps` map and add more dependencies from execution
733 /// of one build script to execution of another build script.
734 fn connect_run_custom_build_deps(unit_dependencies: &mut UnitGraph<'_>) {
735 let mut new_deps = Vec::new();
736
737 {
738 // First up build a reverse dependency map. This is a mapping of all
739 // `RunCustomBuild` known steps to the unit which depends on them. For
740 // example a library might depend on a build script, so this map will
741 // have the build script as the key and the library would be in the
742 // value's set.
743 let mut reverse_deps_map = HashMap::new();
744 for (unit, deps) in unit_dependencies.iter() {
745 for dep in deps {
746 if dep.unit.mode == CompileMode::RunCustomBuild {
747 reverse_deps_map
748 .entry(dep.unit)
749 .or_insert_with(HashSet::new)
750 .insert(unit);
751 }
752 }
753 }
754
755 // Next, we take a look at all build scripts executions listed in the
756 // dependency map. Our job here is to take everything that depends on
757 // this build script (from our reverse map above) and look at the other
758 // package dependencies of these parents.
759 //
760 // If we depend on a linkable target and the build script mentions
761 // `links`, then we depend on that package's build script! Here we use
762 // `dep_build_script` to manufacture an appropriate build script unit to
763 // depend on.
764 for unit in unit_dependencies
765 .keys()
766 .filter(|k| k.mode == CompileMode::RunCustomBuild)
767 {
768 // This is the lib that runs this custom build.
769 let reverse_deps = match reverse_deps_map.get(unit) {
770 Some(set) => set,
771 None => continue,
772 };
773
774 let to_add = reverse_deps
775 .iter()
776 // Get all deps for lib.
777 .flat_map(|reverse_dep| unit_dependencies[reverse_dep].iter())
778 // Only deps with `links`.
779 .filter(|other| {
780 other.unit.pkg != unit.pkg
781 && other.unit.target.linkable()
782 && other.unit.pkg.manifest().links().is_some()
783 })
784 // Get the RunCustomBuild for other lib.
785 .filter_map(|other| {
786 unit_dependencies[&other.unit]
787 .iter()
788 .find(|other_dep| other_dep.unit.mode == CompileMode::RunCustomBuild)
789 .cloned()
790 })
791 .collect::<HashSet<_>>();
792
793 if !to_add.is_empty() {
794 // (RunCustomBuild, set(other RunCustomBuild))
795 new_deps.push((*unit, to_add));
796 }
797 }
798 }
799
800 // And finally, add in all the missing dependencies!
801 for (unit, new_deps) in new_deps {
802 unit_dependencies.get_mut(&unit).unwrap().extend(new_deps);
803 }
804 }
805
806 impl<'a, 'cfg> State<'a, 'cfg> {
807 fn resolve(&self) -> &'a Resolve {
808 if self.is_std {
809 self.std_resolve.unwrap()
810 } else {
811 self.usr_resolve
812 }
813 }
814
815 fn get(&mut self, id: PackageId) -> CargoResult<Option<&'a Package>> {
816 if let Some(pkg) = self.package_cache.get(&id) {
817 return Ok(Some(pkg));
818 }
819 if !self.waiting_on_download.insert(id) {
820 return Ok(None);
821 }
822 if let Some(pkg) = self.downloads.start(id)? {
823 self.package_cache.insert(id, pkg);
824 self.waiting_on_download.remove(&id);
825 return Ok(Some(pkg));
826 }
827 Ok(None)
828 }
829
830 /// Completes at least one downloading, maybe waiting for more to complete.
831 ///
832 /// This function will block the current thread waiting for at least one
833 /// crate to finish downloading. The function may continue to download more
834 /// crates if it looks like there's a long enough queue of crates to keep
835 /// downloading. When only a handful of packages remain this function
836 /// returns, and it's hoped that by returning we'll be able to push more
837 /// packages to download into the queue.
838 fn finish_some_downloads(&mut self) -> CargoResult<()> {
839 assert!(self.downloads.remaining() > 0);
840 loop {
841 let pkg = self.downloads.wait()?;
842 self.waiting_on_download.remove(&pkg.package_id());
843 self.package_cache.insert(pkg.package_id(), pkg);
844
845 // Arbitrarily choose that 5 or more packages concurrently download
846 // is a good enough number to "fill the network pipe". If we have
847 // less than this let's recompute the whole unit dependency graph
848 // again and try to find some more packages to download.
849 if self.downloads.remaining() < 5 {
850 break;
851 }
852 }
853 Ok(())
854 }
855 }