]> git.proxmox.com Git - cargo.git/blobdiff - src/cargo/core/compiler/unit_dependencies.rs
Move string interning to util
[cargo.git] / src / cargo / core / compiler / unit_dependencies.rs
index b58a0ea332acb07ac5e5d3820a76cfd4c48bbb69..5bd8c0aff8735b2133639ff228e5253e3960791f 100644 (file)
 //! 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>,
@@ -38,28 +43,43 @@ struct State<'a, 'cfg> {
     /// 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)?;
@@ -87,34 +107,33 @@ pub fn build_unit_dependencies<'a, 'cfg>(
 }
 
 /// 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?
@@ -133,18 +152,16 @@ fn attach_std_deps<'a, 'cfg>(
 
 /// 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.
@@ -164,11 +181,7 @@ fn deps_of_roots<'a, 'cfg>(roots: &[Unit<'a>], mut state: &mut State<'a, 'cfg>)
 }
 
 /// 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
@@ -177,7 +190,9 @@ fn deps_of<'a, 'cfg>(
     // 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)?;
         }
@@ -189,11 +204,11 @@ fn deps_of<'a, 'cfg>(
 /// 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() {
@@ -201,7 +216,6 @@ fn compute_deps<'a, 'cfg>(
         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());
@@ -225,7 +239,7 @@ fn compute_deps<'a, 'cfg>(
 
             // 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;
             }
 
@@ -261,7 +275,8 @@ fn compute_deps<'a, 'cfg>(
             // 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 =
@@ -309,26 +324,33 @@ fn compute_deps<'a, 'cfg>(
                 .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>>>()?,
         );
     }
 
@@ -339,13 +361,17 @@ fn compute_deps<'a, 'cfg>(
 ///
 /// 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());
         }
@@ -366,8 +392,8 @@ fn compute_deps_custom_build<'a, 'cfg>(
     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,
@@ -377,17 +403,14 @@ fn compute_deps_custom_build<'a, 'cfg>(
 }
 
 /// 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,
             })
         });
@@ -443,21 +466,21 @@ fn compute_deps_doc<'a, 'cfg>(
     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),
@@ -474,11 +497,11 @@ fn maybe_lib<'a>(
 /// 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()
@@ -486,10 +509,7 @@ fn dep_build_script<'a>(
         .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
@@ -519,7 +539,7 @@ fn dep_build_script<'a>(
             new_unit_dep_with_profile(
                 state,
                 unit,
-                unit.pkg,
+                &unit.pkg,
                 t,
                 script_unit_for,
                 unit.kind,
@@ -549,34 +569,36 @@ fn check_or_build_mode(mode: CompileMode, target: &Target) -> CompileMode {
 }
 
 /// 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(),
@@ -589,8 +611,7 @@ fn new_unit_dep_with_profile<'a>(
     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,
@@ -611,7 +632,7 @@ fn new_unit_dep_with_profile<'a>(
 ///
 /// 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();
 
     {
@@ -625,7 +646,7 @@ fn connect_run_custom_build_deps(unit_dependencies: &mut UnitGraph<'_>) {
             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);
                 }
@@ -658,7 +679,7 @@ fn connect_run_custom_build_deps(unit_dependencies: &mut UnitGraph<'_>) {
                 // 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.
@@ -672,7 +693,7 @@ fn connect_run_custom_build_deps(unit_dependencies: &mut UnitGraph<'_>) {
 
             if !to_add.is_empty() {
                 // (RunCustomBuild, set(other RunCustomBuild))
-                new_deps.push((*unit, to_add));
+                new_deps.push((unit.clone(), to_add));
             }
         }
     }
@@ -692,22 +713,25 @@ impl<'a, 'cfg> State<'a, 'cfg> {
         }
     }
 
+    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))
     }