//! graph of `Unit`s, which capture these properties.
use crate::core::compiler::unit_graph::{UnitDep, UnitGraph};
-use crate::core::compiler::Unit;
-use crate::core::compiler::{BuildContext, CompileKind, CompileMode};
+use crate::core::compiler::UnitInterner;
+use crate::core::compiler::{CompileKind, CompileMode, RustcTargetData, Unit};
use crate::core::dependency::DepKind;
-use crate::core::profiles::{Profile, UnitFor};
+use crate::core::profiles::{Profile, Profiles, UnitFor};
use crate::core::resolver::features::{FeaturesFor, ResolvedFeatures};
use crate::core::resolver::Resolve;
-use crate::core::{InternedString, Package, PackageId, Target};
+use crate::core::{Package, PackageId, PackageSet, Target, Workspace};
+use crate::ops::resolve_all_features;
+use crate::util::interning::InternedString;
+use crate::util::Config;
use crate::CargoResult;
use log::trace;
use std::collections::{HashMap, HashSet};
/// Collection of stuff used while creating the `UnitGraph`.
struct State<'a, 'cfg> {
- bcx: &'a BuildContext<'a, 'cfg>,
- unit_dependencies: UnitGraph<'a>,
+ ws: &'a Workspace<'cfg>,
+ config: &'cfg Config,
+ unit_dependencies: UnitGraph,
+ package_set: &'a PackageSet<'cfg>,
usr_resolve: &'a Resolve,
usr_features: &'a ResolvedFeatures,
std_resolve: Option<&'a Resolve>,
/// This flag is `true` while generating the dependencies for the standard
/// library.
is_std: bool,
+ global_mode: CompileMode,
+ target_data: &'a RustcTargetData,
+ profiles: &'a Profiles,
+ interner: &'a UnitInterner,
}
pub fn build_unit_dependencies<'a, 'cfg>(
- bcx: &'a BuildContext<'a, 'cfg>,
+ ws: &'a Workspace<'cfg>,
+ package_set: &'a PackageSet<'cfg>,
resolve: &'a Resolve,
features: &'a ResolvedFeatures,
std_resolve: Option<&'a (Resolve, ResolvedFeatures)>,
- roots: &[Unit<'a>],
- std_roots: &[Unit<'a>],
-) -> CargoResult<UnitGraph<'a>> {
+ roots: &[Unit],
+ std_roots: &HashMap<CompileKind, Vec<Unit>>,
+ global_mode: CompileMode,
+ target_data: &'a RustcTargetData,
+ profiles: &'a Profiles,
+ interner: &'a UnitInterner,
+) -> CargoResult<UnitGraph> {
let (std_resolve, std_features) = match std_resolve {
Some((r, f)) => (Some(r), Some(f)),
None => (None, None),
};
let mut state = State {
- bcx,
+ ws,
+ config: ws.config(),
unit_dependencies: HashMap::new(),
+ package_set,
usr_resolve: resolve,
usr_features: features,
std_resolve,
std_features,
is_std: false,
+ global_mode,
+ target_data,
+ profiles,
+ interner,
};
let std_unit_deps = calc_deps_of_std(&mut state, std_roots)?;
}
/// Compute all the dependencies for the standard library.
-fn calc_deps_of_std<'a, 'cfg>(
- mut state: &mut State<'a, 'cfg>,
- std_roots: &[Unit<'a>],
-) -> CargoResult<Option<UnitGraph<'a>>> {
+fn calc_deps_of_std(
+ mut state: &mut State<'_, '_>,
+ std_roots: &HashMap<CompileKind, Vec<Unit>>,
+) -> CargoResult<Option<UnitGraph>> {
if std_roots.is_empty() {
return Ok(None);
}
// Compute dependencies for the standard library.
state.is_std = true;
- deps_of_roots(std_roots, &mut state)?;
+ for roots in std_roots.values() {
+ deps_of_roots(roots, &mut state)?;
+ }
state.is_std = false;
- Ok(Some(std::mem::replace(
- &mut state.unit_dependencies,
- HashMap::new(),
- )))
+ Ok(Some(std::mem::take(&mut state.unit_dependencies)))
}
/// Add the standard library units to the `unit_dependencies`.
-fn attach_std_deps<'a, 'cfg>(
- state: &mut State<'a, 'cfg>,
- std_roots: &[Unit<'a>],
- std_unit_deps: UnitGraph<'a>,
+fn attach_std_deps(
+ state: &mut State<'_, '_>,
+ std_roots: &HashMap<CompileKind, Vec<Unit>>,
+ std_unit_deps: UnitGraph,
) {
// Attach the standard library as a dependency of every target unit.
for (unit, deps) in state.unit_dependencies.iter_mut() {
if !unit.kind.is_host() && !unit.mode.is_run_custom_build() {
- deps.extend(std_roots.iter().map(|unit| UnitDep {
- unit: *unit,
+ deps.extend(std_roots[&unit.kind].iter().map(|unit| UnitDep {
+ unit: unit.clone(),
unit_for: UnitFor::new_normal(),
extern_crate_name: unit.pkg.name(),
// TODO: Does this `public` make sense?
/// Compute all the dependencies of the given root units.
/// The result is stored in state.unit_dependencies.
-fn deps_of_roots<'a, 'cfg>(roots: &[Unit<'a>], mut state: &mut State<'a, 'cfg>) -> CargoResult<()> {
+fn deps_of_roots(roots: &[Unit], mut state: &mut State<'_, '_>) -> CargoResult<()> {
for unit in roots.iter() {
- state.get(unit.pkg.package_id());
-
// Dependencies of tests/benches should not have `panic` set.
// We check the global test mode to see if we are running in `cargo
// test` in which case we ensure all dependencies have `panic`
// cleared, and avoid building the lib thrice (once with `panic`, once
// without, once for `--test`). In particular, the lib included for
// Doc tests and examples are `Build` mode here.
- let unit_for = if unit.mode.is_any_test() || state.bcx.build_config.test() {
- UnitFor::new_test(state.bcx.config)
+ let unit_for = if unit.mode.is_any_test() || state.global_mode.is_rustc_test() {
+ UnitFor::new_test(state.config)
} else if unit.target.is_custom_build() {
// This normally doesn't happen, except `clean` aggressively
// generates all units.
}
/// Compute the dependencies of a single unit.
-fn deps_of<'a, 'cfg>(
- unit: &Unit<'a>,
- state: &mut State<'a, 'cfg>,
- unit_for: UnitFor,
-) -> CargoResult<()> {
+fn deps_of(unit: &Unit, state: &mut State<'_, '_>, unit_for: UnitFor) -> CargoResult<()> {
// Currently the `unit_dependencies` map does not include `unit_for`. This should
// be safe for now. `TestDependency` only exists to clear the `panic`
// flag, and you'll never ask for a `unit` with `panic` set as a
// affect anything else in the hierarchy.
if !state.unit_dependencies.contains_key(unit) {
let unit_deps = compute_deps(unit, state, unit_for)?;
- state.unit_dependencies.insert(*unit, unit_deps.clone());
+ state
+ .unit_dependencies
+ .insert(unit.clone(), unit_deps.clone());
for unit_dep in unit_deps {
deps_of(&unit_dep.unit, state, unit_dep.unit_for)?;
}
/// for that package.
/// This returns a `Vec` of `(Unit, UnitFor)` pairs. The `UnitFor`
/// is the profile type that should be used for dependencies of the unit.
-fn compute_deps<'a, 'cfg>(
- unit: &Unit<'a>,
- state: &mut State<'a, 'cfg>,
+fn compute_deps(
+ unit: &Unit,
+ state: &mut State<'_, '_>,
unit_for: UnitFor,
-) -> CargoResult<Vec<UnitDep<'a>>> {
+) -> CargoResult<Vec<UnitDep>> {
if unit.mode.is_run_custom_build() {
return compute_deps_custom_build(unit, unit_for, state);
} else if unit.mode.is_doc() {
return compute_deps_doc(unit, state);
}
- let bcx = state.bcx;
let id = unit.pkg.package_id();
let filtered_deps = state.resolve().deps(id).filter(|&(_id, deps)| {
assert!(!deps.is_empty());
// If this dependency is only available for certain platforms,
// make sure we're only enabling it for that platform.
- if !bcx.target_data.dep_platform_activated(dep, unit.kind) {
+ if !state.target_data.dep_platform_activated(dep, unit.kind) {
return false;
}
// If it is a custom build script, then it *only* has build dependencies.
.with_host_features(unit.target.is_custom_build() || lib.proc_macro());
- if bcx.config.cli_unstable().dual_proc_macros && lib.proc_macro() && !unit.kind.is_host() {
+ if state.config.cli_unstable().dual_proc_macros && lib.proc_macro() && !unit.kind.is_host()
+ {
let unit_dep = new_unit_dep(state, unit, pkg, lib, dep_unit_for, unit.kind, mode)?;
ret.push(unit_dep);
let unit_dep =
.targets()
.iter()
.filter(|t| {
- let no_required_features = Vec::new();
-
- t.is_bin() &&
- // Skip binaries with required features that have not been selected.
- t.required_features().unwrap_or(&no_required_features).iter().all(|f| {
- unit.features.contains(&InternedString::new(f.as_str()))
- })
+ // Skip binaries with required features that have not been selected.
+ match t.required_features() {
+ Some(rf) if t.is_bin() => {
+ let features = resolve_all_features(
+ state.resolve(),
+ state.features(),
+ state.package_set,
+ id,
+ );
+ rf.iter().all(|f| features.contains(f))
+ }
+ None if t.is_bin() => true,
+ _ => false,
+ }
})
.map(|t| {
new_unit_dep(
state,
unit,
- unit.pkg,
+ &unit.pkg,
t,
UnitFor::new_normal(),
unit.kind.for_target(t),
CompileMode::Build,
)
})
- .collect::<CargoResult<Vec<UnitDep<'a>>>>()?,
+ .collect::<CargoResult<Vec<UnitDep>>>()?,
);
}
///
/// The `unit` provided must represent an execution of a build script, and
/// the returned set of units must all be run before `unit` is run.
-fn compute_deps_custom_build<'a, 'cfg>(
- unit: &Unit<'a>,
+fn compute_deps_custom_build(
+ unit: &Unit,
unit_for: UnitFor,
- state: &mut State<'a, 'cfg>,
-) -> CargoResult<Vec<UnitDep<'a>>> {
+ state: &mut State<'_, '_>,
+) -> CargoResult<Vec<UnitDep>> {
if let Some(links) = unit.pkg.manifest().links() {
- if state.bcx.script_override(links, unit.kind).is_some() {
+ if state
+ .target_data
+ .script_override(links, unit.kind)
+ .is_some()
+ {
// Overridden build scripts don't have any dependencies.
return Ok(Vec::new());
}
let unit_dep = new_unit_dep(
state,
unit,
- unit.pkg,
- unit.target,
+ &unit.pkg,
+ &unit.target,
script_unit_for,
// Build scripts always compiled for the host.
CompileKind::Host,
}
/// Returns the dependencies necessary to document a package.
-fn compute_deps_doc<'a, 'cfg>(
- unit: &Unit<'a>,
- state: &mut State<'a, 'cfg>,
-) -> CargoResult<Vec<UnitDep<'a>>> {
- let bcx = state.bcx;
+fn compute_deps_doc(unit: &Unit, state: &mut State<'_, '_>) -> CargoResult<Vec<UnitDep>> {
+ let target_data = state.target_data;
let deps = state
.resolve()
.deps(unit.pkg.package_id())
.filter(|&(_id, deps)| {
deps.iter().any(|dep| match dep.kind() {
- DepKind::Normal => bcx.target_data.dep_platform_activated(dep, unit.kind),
+ DepKind::Normal => target_data.dep_platform_activated(dep, unit.kind),
_ => false,
})
});
Ok(ret)
}
-fn maybe_lib<'a>(
- unit: &Unit<'a>,
- state: &mut State<'a, '_>,
+fn maybe_lib(
+ unit: &Unit,
+ state: &mut State<'_, '_>,
unit_for: UnitFor,
-) -> CargoResult<Option<UnitDep<'a>>> {
+) -> CargoResult<Option<UnitDep>> {
unit.pkg
.targets()
.iter()
- .find(|t| t.linkable())
+ .find(|t| t.is_linkable())
.map(|t| {
let mode = check_or_build_mode(unit.mode, t);
new_unit_dep(
state,
unit,
- unit.pkg,
+ &unit.pkg,
t,
unit_for,
unit.kind.for_target(t),
/// script itself doesn't have any dependencies, so even in that case a unit
/// of work is still returned. `None` is only returned if the package has no
/// build script.
-fn dep_build_script<'a>(
- unit: &Unit<'a>,
+fn dep_build_script(
+ unit: &Unit,
unit_for: UnitFor,
- state: &State<'a, '_>,
-) -> CargoResult<Option<UnitDep<'a>>> {
+ state: &State<'_, '_>,
+) -> CargoResult<Option<UnitDep>> {
unit.pkg
.targets()
.iter()
.map(|t| {
// The profile stored in the Unit is the profile for the thing
// the custom build script is running for.
- let profile = state
- .bcx
- .profiles
- .get_profile_run_custom_build(&unit.profile);
+ let profile = state.profiles.get_profile_run_custom_build(&unit.profile);
// UnitFor::new_host is used because we want the `host` flag set
// for all of our build dependencies (so they all get
// build-override profiles), including compiling the build.rs
new_unit_dep_with_profile(
state,
unit,
- unit.pkg,
+ &unit.pkg,
t,
script_unit_for,
unit.kind,
}
/// Create a new Unit for a dependency from `parent` to `pkg` and `target`.
-fn new_unit_dep<'a>(
- state: &State<'a, '_>,
- parent: &Unit<'a>,
- pkg: &'a Package,
- target: &'a Target,
+fn new_unit_dep(
+ state: &State<'_, '_>,
+ parent: &Unit,
+ pkg: &Package,
+ target: &Target,
unit_for: UnitFor,
kind: CompileKind,
mode: CompileMode,
-) -> CargoResult<UnitDep<'a>> {
- let profile = state.bcx.profiles.get_profile(
+) -> CargoResult<UnitDep> {
+ let is_local = pkg.package_id().source_id().is_path() && !state.is_std;
+ let profile = state.profiles.get_profile(
pkg.package_id(),
- state.bcx.ws.is_member(pkg),
+ state.ws.is_member(pkg),
+ is_local,
unit_for,
mode,
);
new_unit_dep_with_profile(state, parent, pkg, target, unit_for, kind, mode, profile)
}
-fn new_unit_dep_with_profile<'a>(
- state: &State<'a, '_>,
- parent: &Unit<'a>,
- pkg: &'a Package,
- target: &'a Target,
+fn new_unit_dep_with_profile(
+ state: &State<'_, '_>,
+ parent: &Unit,
+ pkg: &Package,
+ target: &Target,
unit_for: UnitFor,
kind: CompileKind,
mode: CompileMode,
profile: Profile,
-) -> CargoResult<UnitDep<'a>> {
+) -> CargoResult<UnitDep> {
// TODO: consider making extern_crate_name return InternedString?
let extern_crate_name = InternedString::new(&state.resolve().extern_crate_name(
parent.pkg.package_id(),
let features_for = unit_for.map_to_features_for();
let features = state.activated_features(pkg.package_id(), features_for);
let unit = state
- .bcx
- .units
+ .interner
.intern(pkg, target, profile, kind, mode, features, state.is_std);
Ok(UnitDep {
unit,
///
/// Here we take the entire `deps` map and add more dependencies from execution
/// of one build script to execution of another build script.
-fn connect_run_custom_build_deps(unit_dependencies: &mut UnitGraph<'_>) {
+fn connect_run_custom_build_deps(unit_dependencies: &mut UnitGraph) {
let mut new_deps = Vec::new();
{
for dep in deps {
if dep.unit.mode == CompileMode::RunCustomBuild {
reverse_deps_map
- .entry(dep.unit)
+ .entry(dep.unit.clone())
.or_insert_with(HashSet::new)
.insert(unit);
}
// Only deps with `links`.
.filter(|other| {
other.unit.pkg != unit.pkg
- && other.unit.target.linkable()
+ && other.unit.target.is_linkable()
&& other.unit.pkg.manifest().links().is_some()
})
// Get the RunCustomBuild for other lib.
if !to_add.is_empty() {
// (RunCustomBuild, set(other RunCustomBuild))
- new_deps.push((*unit, to_add));
+ new_deps.push((unit.clone(), to_add));
}
}
}
}
}
+ fn features(&self) -> &'a ResolvedFeatures {
+ if self.is_std {
+ self.std_features.unwrap()
+ } else {
+ self.usr_features
+ }
+ }
+
fn activated_features(
&self,
pkg_id: PackageId,
features_for: FeaturesFor,
) -> Vec<InternedString> {
- let features = if self.is_std {
- self.std_features.unwrap()
- } else {
- self.usr_features
- };
+ let features = self.features();
features.activated_features(pkg_id, features_for)
}
fn get(&self, id: PackageId) -> &'a Package {
- self.bcx
- .packages
+ self.package_set
.get_one(id)
.unwrap_or_else(|_| panic!("expected {} to be downloaded", id))
}