Skip to content

Commit 9a8d695

Browse files
committed
Decouple build_unit_dependencies and Context.
1 parent a7efa91 commit 9a8d695

File tree

5 files changed

+72
-80
lines changed

5 files changed

+72
-80
lines changed

src/cargo/core/compiler/context/mod.rs

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#![allow(deprecated)]
2-
use std::collections::{HashMap, HashSet};
2+
use std::collections::{BTreeSet, HashMap, HashSet};
33
use std::ffi::OsStr;
44
use std::fmt::Write;
55
use std::path::PathBuf;
@@ -10,7 +10,7 @@ use jobserver::Client;
1010

1111
use crate::core::compiler::compilation;
1212
use crate::core::compiler::Unit;
13-
use crate::core::{Package, PackageId, Resolve};
13+
use crate::core::{PackageId, Resolve};
1414
use crate::util::errors::{CargoResult, CargoResultExt};
1515
use crate::util::{internal, profile, Config};
1616

@@ -21,9 +21,6 @@ use super::job_queue::JobQueue;
2121
use super::layout::Layout;
2222
use super::{BuildContext, Compilation, CompileMode, Executor, FileFlavor, Kind};
2323

24-
mod unit_dependencies;
25-
use self::unit_dependencies::build_unit_dependencies;
26-
2724
mod compilation_files;
2825
use self::compilation_files::CompilationFiles;
2926
pub use self::compilation_files::{Metadata, OutputFile};
@@ -66,8 +63,6 @@ pub struct Context<'a, 'cfg> {
6663
/// the compilation. This is `None` until after `unit_dependencies` has
6764
/// been computed.
6865
files: Option<CompilationFiles<'a, 'cfg>>,
69-
/// Cache of packages, populated when they are downloaded.
70-
package_cache: HashMap<PackageId, &'a Package>,
7166

7267
/// A flag indicating whether pipelining is enabled for this compilation
7368
/// session. Pipelining largely only affects the edges of the dependency
@@ -82,7 +77,11 @@ pub struct Context<'a, 'cfg> {
8277
}
8378

8479
impl<'a, 'cfg> Context<'a, 'cfg> {
85-
pub fn new(config: &'cfg Config, bcx: &'a BuildContext<'a, 'cfg>) -> CargoResult<Self> {
80+
pub fn new(
81+
config: &'cfg Config,
82+
bcx: &'a BuildContext<'a, 'cfg>,
83+
unit_dependencies: HashMap<Unit<'a>, Vec<Unit<'a>>>,
84+
) -> CargoResult<Self> {
8685
// Load up the jobserver that we'll use to manage our parallelism. This
8786
// is the same as the GNU make implementation of a jobserver, and
8887
// intentionally so! It's hoped that we can interact with GNU make and
@@ -115,9 +114,8 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
115114
links: Links::new(),
116115
jobserver,
117116
primary_packages: HashSet::new(),
118-
unit_dependencies: HashMap::new(),
117+
unit_dependencies,
119118
files: None,
120-
package_cache: HashMap::new(),
121119
rmeta_required: HashSet::new(),
122120
pipelining,
123121
})
@@ -305,7 +303,8 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
305303
self.primary_packages
306304
.extend(units.iter().map(|u| u.pkg.package_id()));
307305

308-
build_unit_dependencies(self, units)?;
306+
self.record_units_requiring_metadata();
307+
309308
let files = CompilationFiles::new(
310309
units,
311310
host_layout,
@@ -367,28 +366,19 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
367366
self.primary_packages.contains(&unit.pkg.package_id())
368367
}
369368

370-
/// Gets a package for the given package ID.
371-
pub fn get_package(&self, id: PackageId) -> CargoResult<&'a Package> {
372-
self.package_cache
373-
.get(&id)
374-
.cloned()
375-
.ok_or_else(|| failure::format_err!("failed to find {}", id))
376-
}
377-
378369
/// Returns the list of filenames read by cargo to generate the `BuildContext`
379370
/// (all `Cargo.toml`, etc.).
380371
pub fn build_plan_inputs(&self) -> CargoResult<Vec<PathBuf>> {
381-
let mut inputs = Vec::new();
372+
let mut inputs = BTreeSet::new();
382373
// Note that we're using the `package_cache`, which should have been
383374
// populated by `build_unit_dependencies`, and only those packages are
384375
// considered as all the inputs.
385376
//
386377
// (Notably, we skip dev-deps here if they aren't present.)
387-
for pkg in self.package_cache.values() {
388-
inputs.push(pkg.manifest_path().to_path_buf());
378+
for unit in self.unit_dependencies.keys() {
379+
inputs.insert(unit.pkg.manifest_path().to_path_buf());
389380
}
390-
inputs.sort();
391-
Ok(inputs)
381+
Ok(inputs.into_iter().collect())
392382
}
393383

394384
fn check_collistions(&self) -> CargoResult<()> {
@@ -488,6 +478,20 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
488478
Ok(())
489479
}
490480

481+
/// Records the list of units which are required to emit metadata.
482+
///
483+
/// Units which depend only on the metadata of others requires the others to
484+
/// actually produce metadata, so we'll record that here.
485+
fn record_units_requiring_metadata(&mut self) {
486+
for (key, deps) in self.unit_dependencies.iter() {
487+
for dep in deps {
488+
if self.only_requires_rmeta(key, dep) {
489+
self.rmeta_required.insert(*dep);
490+
}
491+
}
492+
}
493+
}
494+
491495
/// Returns whether when `parent` depends on `dep` if it only requires the
492496
/// metadata file from `dep`.
493497
pub fn only_requires_rmeta(&self, parent: &Unit<'a>, dep: &Unit<'a>) -> bool {

src/cargo/core/compiler/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ mod job_queue;
1010
mod layout;
1111
mod output_depinfo;
1212
mod unit;
13+
mod unit_dependencies;
1314

1415
use std::env;
1516
use std::ffi::{OsStr, OsString};
@@ -35,6 +36,7 @@ use self::job::{Job, Work};
3536
use self::job_queue::{JobQueue, JobState};
3637
pub use self::layout::is_bad_artifact_name;
3738
use self::output_depinfo::output_depinfo;
39+
pub use self::unit_dependencies::build_unit_dependencies;
3840
pub use crate::core::compiler::unit::{Unit, UnitInterner};
3941
use crate::core::manifest::TargetSourcePath;
4042
use crate::core::profiles::{Lto, PanicStrategy, Profile};

src/cargo/core/compiler/context/unit_dependencies.rs renamed to src/cargo/core/compiler/unit_dependencies.rs

Lines changed: 35 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
//! graph of `Unit`s, which capture these properties.
1717
1818
use crate::core::compiler::Unit;
19-
use crate::core::compiler::{BuildContext, CompileMode, Context, Kind};
19+
use crate::core::compiler::{BuildContext, CompileMode, Kind};
2020
use crate::core::dependency::Kind as DepKind;
2121
use crate::core::package::Downloads;
2222
use crate::core::profiles::UnitFor;
@@ -25,25 +25,24 @@ use crate::CargoResult;
2525
use log::trace;
2626
use std::collections::{HashMap, HashSet};
2727

28-
struct State<'a, 'cfg, 'tmp> {
29-
cx: &'tmp mut Context<'a, 'cfg>,
28+
struct State<'a, 'cfg> {
29+
bcx: &'a BuildContext<'a, 'cfg>,
3030
waiting_on_download: HashSet<PackageId>,
3131
downloads: Downloads<'a, 'cfg>,
32+
unit_dependencies: HashMap<Unit<'a>, Vec<Unit<'a>>>,
33+
package_cache: HashMap<PackageId, &'a Package>,
3234
}
3335

3436
pub fn build_unit_dependencies<'a, 'cfg>(
35-
cx: &mut Context<'a, 'cfg>,
37+
bcx: &'a BuildContext<'a, 'cfg>,
3638
roots: &[Unit<'a>],
37-
) -> CargoResult<()> {
38-
assert!(
39-
cx.unit_dependencies.is_empty(),
40-
"can only build unit deps once"
41-
);
42-
39+
) -> CargoResult<HashMap<Unit<'a>, Vec<Unit<'a>>>> {
4340
let mut state = State {
44-
downloads: cx.bcx.packages.enable_download()?,
45-
cx,
41+
bcx,
42+
downloads: bcx.packages.enable_download()?,
4643
waiting_on_download: HashSet::new(),
44+
unit_dependencies: HashMap::new(),
45+
package_cache: HashMap::new(),
4746
};
4847

4948
loop {
@@ -56,7 +55,7 @@ pub fn build_unit_dependencies<'a, 'cfg>(
5655
// cleared, and avoid building the lib thrice (once with `panic`, once
5756
// without, once for `--test`). In particular, the lib included for
5857
// Doc tests and examples are `Build` mode here.
59-
let unit_for = if unit.mode.is_any_test() || state.cx.bcx.build_config.test() {
58+
let unit_for = if unit.mode.is_any_test() || state.bcx.build_config.test() {
6059
UnitFor::new_test()
6160
} else if unit.target.is_custom_build() {
6261
// This normally doesn't happen, except `clean` aggressively
@@ -73,32 +72,30 @@ pub fn build_unit_dependencies<'a, 'cfg>(
7372

7473
if !state.waiting_on_download.is_empty() {
7574
state.finish_some_downloads()?;
76-
state.cx.unit_dependencies.clear();
75+
state.unit_dependencies.clear();
7776
} else {
7877
break;
7978
}
8079
}
8180

8281
connect_run_custom_build_deps(&mut state);
8382

84-
trace!("ALL UNIT DEPENDENCIES {:#?}", state.cx.unit_dependencies);
85-
86-
record_units_requiring_metadata(state.cx);
83+
trace!("ALL UNIT DEPENDENCIES {:#?}", state.unit_dependencies);
8784

8885
// Dependencies are used in tons of places throughout the backend, many of
8986
// which affect the determinism of the build itself. As a result be sure
9087
// that dependency lists are always sorted to ensure we've always got a
9188
// deterministic output.
92-
for list in state.cx.unit_dependencies.values_mut() {
89+
for list in state.unit_dependencies.values_mut() {
9390
list.sort();
9491
}
9592

96-
Ok(())
93+
Ok(state.unit_dependencies)
9794
}
9895

99-
fn deps_of<'a, 'cfg, 'tmp>(
96+
fn deps_of<'a, 'cfg>(
10097
unit: &Unit<'a>,
101-
state: &mut State<'a, 'cfg, 'tmp>,
98+
state: &mut State<'a, 'cfg>,
10299
unit_for: UnitFor,
103100
) -> CargoResult<()> {
104101
// Currently the `unit_dependencies` map does not include `unit_for`. This should
@@ -107,10 +104,10 @@ fn deps_of<'a, 'cfg, 'tmp>(
107104
// `TestDependency`. `CustomBuild` should also be fine since if the
108105
// requested unit's settings are the same as `Any`, `CustomBuild` can't
109106
// affect anything else in the hierarchy.
110-
if !state.cx.unit_dependencies.contains_key(unit) {
107+
if !state.unit_dependencies.contains_key(unit) {
111108
let unit_deps = compute_deps(unit, state, unit_for)?;
112109
let to_insert: Vec<_> = unit_deps.iter().map(|&(unit, _)| unit).collect();
113-
state.cx.unit_dependencies.insert(*unit, to_insert);
110+
state.unit_dependencies.insert(*unit, to_insert);
114111
for (unit, unit_for) in unit_deps {
115112
deps_of(&unit, state, unit_for)?;
116113
}
@@ -122,19 +119,19 @@ fn deps_of<'a, 'cfg, 'tmp>(
122119
/// for that package.
123120
/// This returns a `Vec` of `(Unit, UnitFor)` pairs. The `UnitFor`
124121
/// is the profile type that should be used for dependencies of the unit.
125-
fn compute_deps<'a, 'cfg, 'tmp>(
122+
fn compute_deps<'a, 'cfg>(
126123
unit: &Unit<'a>,
127-
state: &mut State<'a, 'cfg, 'tmp>,
124+
state: &mut State<'a, 'cfg>,
128125
unit_for: UnitFor,
129126
) -> CargoResult<Vec<(Unit<'a>, UnitFor)>> {
130127
if unit.mode.is_run_custom_build() {
131-
return compute_deps_custom_build(unit, state.cx.bcx);
128+
return compute_deps_custom_build(unit, state.bcx);
132129
} else if unit.mode.is_doc() {
133130
// Note: this does not include doc test.
134131
return compute_deps_doc(unit, state);
135132
}
136133

137-
let bcx = state.cx.bcx;
134+
let bcx = state.bcx;
138135
let id = unit.pkg.package_id();
139136
let deps = bcx.resolve.deps(id).filter(|&(_id, deps)| {
140137
assert!(!deps.is_empty());
@@ -289,11 +286,11 @@ fn compute_deps_custom_build<'a, 'cfg>(
289286
}
290287

291288
/// Returns the dependencies necessary to document a package.
292-
fn compute_deps_doc<'a, 'cfg, 'tmp>(
289+
fn compute_deps_doc<'a, 'cfg>(
293290
unit: &Unit<'a>,
294-
state: &mut State<'a, 'cfg, 'tmp>,
291+
state: &mut State<'a, 'cfg>,
295292
) -> CargoResult<Vec<(Unit<'a>, UnitFor)>> {
296-
let bcx = state.cx.bcx;
293+
let bcx = state.bcx;
297294
let deps = bcx
298295
.resolve
299296
.deps(unit.pkg.package_id())
@@ -438,7 +435,7 @@ fn new_unit<'a>(
438435
///
439436
/// Here we take the entire `deps` map and add more dependencies from execution
440437
/// of one build script to execution of another build script.
441-
fn connect_run_custom_build_deps(state: &mut State<'_, '_, '_>) {
438+
fn connect_run_custom_build_deps(state: &mut State<'_, '_>) {
442439
let mut new_deps = Vec::new();
443440

444441
{
@@ -448,7 +445,7 @@ fn connect_run_custom_build_deps(state: &mut State<'_, '_, '_>) {
448445
// have the build script as the key and the library would be in the
449446
// value's set.
450447
let mut reverse_deps = HashMap::new();
451-
for (unit, deps) in state.cx.unit_dependencies.iter() {
448+
for (unit, deps) in state.unit_dependencies.iter() {
452449
for dep in deps {
453450
if dep.mode == CompileMode::RunCustomBuild {
454451
reverse_deps
@@ -469,7 +466,6 @@ fn connect_run_custom_build_deps(state: &mut State<'_, '_, '_>) {
469466
// `dep_build_script` to manufacture an appropriate build script unit to
470467
// depend on.
471468
for unit in state
472-
.cx
473469
.unit_dependencies
474470
.keys()
475471
.filter(|k| k.mode == CompileMode::RunCustomBuild)
@@ -481,13 +477,13 @@ fn connect_run_custom_build_deps(state: &mut State<'_, '_, '_>) {
481477

482478
let to_add = reverse_deps
483479
.iter()
484-
.flat_map(|reverse_dep| state.cx.unit_dependencies[reverse_dep].iter())
480+
.flat_map(|reverse_dep| state.unit_dependencies[reverse_dep].iter())
485481
.filter(|other| {
486482
other.pkg != unit.pkg
487483
&& other.target.linkable()
488484
&& other.pkg.manifest().links().is_some()
489485
})
490-
.filter_map(|other| dep_build_script(other, state.cx.bcx).map(|p| p.0))
486+
.filter_map(|other| dep_build_script(other, state.bcx).map(|p| p.0))
491487
.collect::<HashSet<_>>();
492488

493489
if !to_add.is_empty() {
@@ -499,38 +495,23 @@ fn connect_run_custom_build_deps(state: &mut State<'_, '_, '_>) {
499495
// And finally, add in all the missing dependencies!
500496
for (unit, new_deps) in new_deps {
501497
state
502-
.cx
503498
.unit_dependencies
504499
.get_mut(&unit)
505500
.unwrap()
506501
.extend(new_deps);
507502
}
508503
}
509504

510-
/// Records the list of units which are required to emit metadata.
511-
///
512-
/// Units which depend only on the metadata of others requires the others to
513-
/// actually produce metadata, so we'll record that here.
514-
fn record_units_requiring_metadata(cx: &mut Context<'_, '_>) {
515-
for (key, deps) in cx.unit_dependencies.iter() {
516-
for dep in deps {
517-
if cx.only_requires_rmeta(key, dep) {
518-
cx.rmeta_required.insert(*dep);
519-
}
520-
}
521-
}
522-
}
523-
524-
impl<'a, 'cfg, 'tmp> State<'a, 'cfg, 'tmp> {
505+
impl<'a, 'cfg> State<'a, 'cfg> {
525506
fn get(&mut self, id: PackageId) -> CargoResult<Option<&'a Package>> {
526-
if let Some(pkg) = self.cx.package_cache.get(&id) {
507+
if let Some(pkg) = self.package_cache.get(&id) {
527508
return Ok(Some(pkg));
528509
}
529510
if !self.waiting_on_download.insert(id) {
530511
return Ok(None);
531512
}
532513
if let Some(pkg) = self.downloads.start(id)? {
533-
self.cx.package_cache.insert(id, pkg);
514+
self.package_cache.insert(id, pkg);
534515
self.waiting_on_download.remove(&id);
535516
return Ok(Some(pkg));
536517
}
@@ -550,7 +531,7 @@ impl<'a, 'cfg, 'tmp> State<'a, 'cfg, 'tmp> {
550531
loop {
551532
let pkg = self.downloads.wait()?;
552533
self.waiting_on_download.remove(&pkg.package_id());
553-
self.cx.package_cache.insert(pkg.package_id(), pkg);
534+
self.package_cache.insert(pkg.package_id(), pkg);
554535

555536
// Arbitrarily choose that 5 or more packages concurrently download
556537
// is a good enough number to "fill the network pipe". If we have

src/cargo/ops/cargo_clean.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::collections::HashMap;
22
use std::fs;
33
use std::path::Path;
44

5+
use crate::core::compiler::build_unit_dependencies;
56
use crate::core::compiler::UnitInterner;
67
use crate::core::compiler::{BuildConfig, BuildContext, CompileMode, Context, Kind};
78
use crate::core::profiles::UnitFor;
@@ -104,7 +105,8 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> {
104105
}
105106
}
106107

107-
let mut cx = Context::new(config, &bcx)?;
108+
let unit_dependencies = build_unit_dependencies(&bcx, &units)?;
109+
let mut cx = Context::new(config, &bcx, unit_dependencies)?;
108110
cx.prepare_units(None, &units)?;
109111

110112
for unit in units.iter() {

0 commit comments

Comments
 (0)