Skip to content

Commit 944f504

Browse files
committed
Re-implement proc-macro feature decoupling.
1 parent 7dec94d commit 944f504

File tree

21 files changed

+190
-256
lines changed

21 files changed

+190
-256
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ path = "src/cargo/lib.rs"
2222
atty = "0.2"
2323
bytesize = "1.0"
2424
cargo-platform = { path = "crates/cargo-platform", version = "0.1.1" }
25-
crates-io = { path = "crates/crates-io", version = "0.32" }
25+
crates-io = { path = "crates/crates-io", version = "0.31" }
2626
crossbeam-utils = "0.7"
2727
crypto-hash = "0.3.1"
2828
curl = { version = "0.4.23", features = ["http2"] }

crates/cargo-test-support/src/registry.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,6 @@ impl Package {
420420
"cksum": cksum,
421421
"features": self.features,
422422
"yanked": self.yanked,
423-
"pm": self.proc_macro,
424423
})
425424
.to_string();
426425

crates/crates-io/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "crates-io"
3-
version = "0.32.0"
3+
version = "0.31.0"
44
edition = "2018"
55
authors = ["Alex Crichton <alex@alexcrichton.com>"]
66
license = "MIT OR Apache-2.0"

crates/crates-io/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ pub struct NewCrate {
5555
pub repository: Option<String>,
5656
pub badges: BTreeMap<String, BTreeMap<String, String>>,
5757
pub links: Option<String>,
58-
pub proc_macro: bool,
5958
}
6059

6160
#[derive(Serialize)]

crates/resolver-tests/src/lib.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,6 @@ pub fn resolve_with_config_raw(
176176
&BTreeMap::<String, Vec<String>>::new(),
177177
None::<&String>,
178178
false,
179-
false,
180179
)
181180
.unwrap();
182181
let opts = ResolveOpts::everything();
@@ -578,7 +577,6 @@ pub fn pkg_dep<T: ToPkgId>(name: T, dep: Vec<Dependency>) -> Summary {
578577
&BTreeMap::<String, Vec<String>>::new(),
579578
link,
580579
false,
581-
false,
582580
)
583581
.unwrap()
584582
}
@@ -607,7 +605,6 @@ pub fn pkg_loc(name: &str, loc: &str) -> Summary {
607605
&BTreeMap::<String, Vec<String>>::new(),
608606
link,
609607
false,
610-
false,
611608
)
612609
.unwrap()
613610
}
@@ -622,7 +619,6 @@ pub fn remove_dep(sum: &Summary, ind: usize) -> Summary {
622619
&BTreeMap::<String, Vec<String>>::new(),
623620
sum.links().map(|a| a.as_str()),
624621
sum.namespaced_features(),
625-
sum.proc_macro(),
626622
)
627623
.unwrap()
628624
}

src/cargo/core/compiler/unit_dependencies.rs

Lines changed: 31 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use crate::core::compiler::unit_graph::{UnitDep, UnitGraph};
1919
use crate::core::compiler::Unit;
2020
use crate::core::compiler::{BuildContext, CompileKind, CompileMode};
2121
use crate::core::dependency::DepKind;
22-
use crate::core::package::Downloads;
2322
use crate::core::profiles::{Profile, UnitFor};
2423
use crate::core::resolver::features::{FeaturesFor, ResolvedFeatures};
2524
use crate::core::resolver::Resolve;
@@ -31,10 +30,7 @@ use std::collections::{HashMap, HashSet};
3130
/// Collection of stuff used while creating the `UnitGraph`.
3231
struct State<'a, 'cfg> {
3332
bcx: &'a BuildContext<'a, 'cfg>,
34-
waiting_on_download: HashSet<PackageId>,
35-
downloads: Downloads<'a, 'cfg>,
3633
unit_dependencies: UnitGraph<'a>,
37-
package_cache: HashMap<PackageId, &'a Package>,
3834
usr_resolve: &'a Resolve,
3935
usr_features: &'a ResolvedFeatures,
4036
std_resolve: Option<&'a Resolve>,
@@ -58,10 +54,7 @@ pub fn build_unit_dependencies<'a, 'cfg>(
5854
};
5955
let mut state = State {
6056
bcx,
61-
downloads: bcx.packages.enable_download()?,
62-
waiting_on_download: HashSet::new(),
6357
unit_dependencies: HashMap::new(),
64-
package_cache: HashMap::new(),
6558
usr_resolve: resolve,
6659
usr_features: features,
6760
std_resolve,
@@ -141,44 +134,32 @@ fn attach_std_deps<'a, 'cfg>(
141134
/// Compute all the dependencies of the given root units.
142135
/// The result is stored in state.unit_dependencies.
143136
fn deps_of_roots<'a, 'cfg>(roots: &[Unit<'a>], mut state: &mut State<'a, 'cfg>) -> CargoResult<()> {
144-
// Loop because we are downloading while building the dependency graph.
145-
// The partially-built unit graph is discarded through each pass of the
146-
// loop because it is incomplete because not all required Packages have
147-
// been downloaded.
148-
loop {
149-
for unit in roots.iter() {
150-
state.get(unit.pkg.package_id())?;
151-
152-
// Dependencies of tests/benches should not have `panic` set.
153-
// We check the global test mode to see if we are running in `cargo
154-
// test` in which case we ensure all dependencies have `panic`
155-
// cleared, and avoid building the lib thrice (once with `panic`, once
156-
// without, once for `--test`). In particular, the lib included for
157-
// Doc tests and examples are `Build` mode here.
158-
let unit_for = if unit.mode.is_any_test() || state.bcx.build_config.test() {
159-
UnitFor::new_test(state.bcx.config)
160-
} else if unit.target.is_custom_build() {
161-
// This normally doesn't happen, except `clean` aggressively
162-
// generates all units.
163-
UnitFor::new_host(false)
164-
} else if unit.target.proc_macro() {
165-
UnitFor::new_host(true)
166-
} else if unit.target.for_host() {
167-
// Plugin should never have panic set.
168-
UnitFor::new_compiler()
169-
} else {
170-
UnitFor::new_normal()
171-
};
172-
deps_of(unit, &mut state, unit_for)?;
173-
}
174-
175-
if !state.waiting_on_download.is_empty() {
176-
state.finish_some_downloads()?;
177-
state.unit_dependencies.clear();
137+
for unit in roots.iter() {
138+
state.get(unit.pkg.package_id());
139+
140+
// Dependencies of tests/benches should not have `panic` set.
141+
// We check the global test mode to see if we are running in `cargo
142+
// test` in which case we ensure all dependencies have `panic`
143+
// cleared, and avoid building the lib thrice (once with `panic`, once
144+
// without, once for `--test`). In particular, the lib included for
145+
// Doc tests and examples are `Build` mode here.
146+
let unit_for = if unit.mode.is_any_test() || state.bcx.build_config.test() {
147+
UnitFor::new_test(state.bcx.config)
148+
} else if unit.target.is_custom_build() {
149+
// This normally doesn't happen, except `clean` aggressively
150+
// generates all units.
151+
UnitFor::new_host(false)
152+
} else if unit.target.proc_macro() {
153+
UnitFor::new_host(true)
154+
} else if unit.target.for_host() {
155+
// Plugin should never have panic set.
156+
UnitFor::new_compiler()
178157
} else {
179-
break;
180-
}
158+
UnitFor::new_normal()
159+
};
160+
deps_of(unit, &mut state, unit_for)?;
181161
}
162+
182163
Ok(())
183164
}
184165

@@ -269,10 +250,7 @@ fn compute_deps<'a, 'cfg>(
269250

270251
let mut ret = Vec::new();
271252
for (id, _) in filtered_deps {
272-
let pkg = match state.get(id)? {
273-
Some(pkg) => pkg,
274-
None => continue,
275-
};
253+
let pkg = state.get(id);
276254
let lib = match pkg.targets().iter().find(|t| t.is_lib()) {
277255
Some(t) => t,
278256
None => continue,
@@ -419,10 +397,7 @@ fn compute_deps_doc<'a, 'cfg>(
419397
// the documentation of the library being built.
420398
let mut ret = Vec::new();
421399
for (id, _deps) in deps {
422-
let dep = match state.get(id)? {
423-
Some(dep) => dep,
424-
None => continue,
425-
};
400+
let dep = state.get(id);
426401
let lib = match dep.targets().iter().find(|t| t.is_lib()) {
427402
Some(lib) => lib,
428403
None => continue,
@@ -730,44 +705,10 @@ impl<'a, 'cfg> State<'a, 'cfg> {
730705
features.activated_features(pkg_id, features_for)
731706
}
732707

733-
fn get(&mut self, id: PackageId) -> CargoResult<Option<&'a Package>> {
734-
if let Some(pkg) = self.package_cache.get(&id) {
735-
return Ok(Some(pkg));
736-
}
737-
if !self.waiting_on_download.insert(id) {
738-
return Ok(None);
739-
}
740-
if let Some(pkg) = self.downloads.start(id)? {
741-
self.package_cache.insert(id, pkg);
742-
self.waiting_on_download.remove(&id);
743-
return Ok(Some(pkg));
744-
}
745-
Ok(None)
746-
}
747-
748-
/// Completes at least one downloading, maybe waiting for more to complete.
749-
///
750-
/// This function will block the current thread waiting for at least one
751-
/// crate to finish downloading. The function may continue to download more
752-
/// crates if it looks like there's a long enough queue of crates to keep
753-
/// downloading. When only a handful of packages remain this function
754-
/// returns, and it's hoped that by returning we'll be able to push more
755-
/// packages to download into the queue.
756-
fn finish_some_downloads(&mut self) -> CargoResult<()> {
757-
assert!(self.downloads.remaining() > 0);
758-
loop {
759-
let pkg = self.downloads.wait()?;
760-
self.waiting_on_download.remove(&pkg.package_id());
761-
self.package_cache.insert(pkg.package_id(), pkg);
762-
763-
// Arbitrarily choose that 5 or more packages concurrently download
764-
// is a good enough number to "fill the network pipe". If we have
765-
// less than this let's recompute the whole unit dependency graph
766-
// again and try to find some more packages to download.
767-
if self.downloads.remaining() < 5 {
768-
break;
769-
}
770-
}
771-
Ok(())
708+
fn get(&self, id: PackageId) -> &'a Package {
709+
self.bcx
710+
.packages
711+
.get_one(id)
712+
.unwrap_or_else(|_| panic!("expected {} to be downloaded", id))
772713
}
773714
}

src/cargo/core/package.rs

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::cell::{Cell, Ref, RefCell, RefMut};
22
use std::cmp::Ordering;
3-
use std::collections::{HashMap, HashSet};
3+
use std::collections::{BTreeSet, HashMap, HashSet};
44
use std::fmt;
55
use std::hash;
66
use std::mem;
@@ -17,7 +17,10 @@ use semver::Version;
1717
use serde::ser;
1818
use serde::Serialize;
1919

20+
use crate::core::compiler::{CompileKind, RustcTargetData};
21+
use crate::core::dependency::DepKind;
2022
use crate::core::interning::InternedString;
23+
use crate::core::resolver::{HasDevUnits, Resolve};
2124
use crate::core::source::MaybePackage;
2225
use crate::core::{Dependency, Manifest, PackageId, SourceId, Target};
2326
use crate::core::{FeatureMap, SourceMap, Summary};
@@ -189,6 +192,10 @@ impl Package {
189192
pub fn publish(&self) -> &Option<Vec<String>> {
190193
self.manifest.publish()
191194
}
195+
/// Returns `true` if this package is a proc-macro.
196+
pub fn proc_macro(&self) -> bool {
197+
self.targets().iter().any(|target| target.proc_macro())
198+
}
192199

193200
/// Returns `true` if the package uses a custom build script for any target.
194201
pub fn has_custom_build(&self) -> bool {
@@ -432,6 +439,9 @@ impl<'cfg> PackageSet<'cfg> {
432439
}
433440

434441
pub fn get_one(&self, id: PackageId) -> CargoResult<&Package> {
442+
if let Some(pkg) = self.packages.get(&id).and_then(|slot| slot.borrow()) {
443+
return Ok(pkg);
444+
}
435445
Ok(self.get_many(Some(id))?.remove(0))
436446
}
437447

@@ -448,6 +458,75 @@ impl<'cfg> PackageSet<'cfg> {
448458
Ok(pkgs)
449459
}
450460

461+
/// Downloads any packages accessible from the give root ids.
462+
pub fn download_accessible(
463+
&self,
464+
resolve: &Resolve,
465+
root_ids: &[PackageId],
466+
has_dev_units: HasDevUnits,
467+
requested_kind: CompileKind,
468+
target_data: &RustcTargetData,
469+
) -> CargoResult<()> {
470+
fn collect_used_deps(
471+
used: &mut BTreeSet<PackageId>,
472+
resolve: &Resolve,
473+
pkg_id: PackageId,
474+
has_dev_units: HasDevUnits,
475+
requested_kind: CompileKind,
476+
target_data: &RustcTargetData,
477+
) -> CargoResult<()> {
478+
if !used.insert(pkg_id) {
479+
return Ok(());
480+
}
481+
let filtered_deps = resolve.deps(pkg_id).filter(|&(_id, deps)| {
482+
deps.iter().any(|dep| {
483+
if dep.kind() == DepKind::Development && has_dev_units == HasDevUnits::No {
484+
return false;
485+
}
486+
// This is overly broad, since not all target-specific
487+
// dependencies are used both for target and host. To tighten this
488+
// up, this function would need to track "for_host" similar to how
489+
// unit dependencies handles it.
490+
if !target_data.dep_platform_activated(dep, requested_kind)
491+
&& !target_data.dep_platform_activated(dep, CompileKind::Host)
492+
{
493+
return false;
494+
}
495+
true
496+
})
497+
});
498+
for (dep_id, _deps) in filtered_deps {
499+
collect_used_deps(
500+
used,
501+
resolve,
502+
dep_id,
503+
has_dev_units,
504+
requested_kind,
505+
target_data,
506+
)?;
507+
}
508+
Ok(())
509+
}
510+
511+
// This is sorted by PackageId to get consistent behavior and error
512+
// messages for Cargo's testsuite. Perhaps there is a better ordering
513+
// that optimizes download time?
514+
let mut to_download = BTreeSet::new();
515+
516+
for id in root_ids {
517+
collect_used_deps(
518+
&mut to_download,
519+
resolve,
520+
*id,
521+
has_dev_units,
522+
requested_kind,
523+
target_data,
524+
)?;
525+
}
526+
self.get_many(to_download.into_iter())?;
527+
Ok(())
528+
}
529+
451530
pub fn sources(&self) -> Ref<'_, SourceMap<'cfg>> {
452531
self.sources.borrow()
453532
}

0 commit comments

Comments
 (0)