]> git.proxmox.com Git - cargo.git/blobdiff - src/cargo/core/compiler/unit_dependencies.rs
Add comment on relationship of RunCustomBuild and UnitFor::host.
[cargo.git] / src / cargo / core / compiler / unit_dependencies.rs
index 1fb61cc5625ea3c68f59a361f4e311092206f2d6..48841defd6f26e9c26bc0a169563c4c6ed2e5a4e 100644 (file)
 
 use crate::core::compiler::Unit;
 use crate::core::compiler::{BuildContext, CompileKind, CompileMode};
-use crate::core::dependency::Kind as DepKind;
+use crate::core::dependency::DepKind;
 use crate::core::package::Downloads;
 use crate::core::profiles::{Profile, UnitFor};
+use crate::core::resolver::features::{FeaturesFor, ResolvedFeatures};
 use crate::core::resolver::Resolve;
 use crate::core::{InternedString, Package, PackageId, Target};
 use crate::CargoResult;
@@ -41,6 +42,8 @@ pub struct UnitDep<'a> {
     pub extern_crate_name: InternedString,
     /// Whether or not this is a public dependency.
     pub public: bool,
+    /// If `true`, the dependency should not be added to Rust's prelude.
+    pub noprelude: bool,
 }
 
 /// Collection of stuff used while creating the `UnitGraph`.
@@ -51,7 +54,9 @@ struct State<'a, 'cfg> {
     unit_dependencies: UnitGraph<'a>,
     package_cache: HashMap<PackageId, &'a Package>,
     usr_resolve: &'a Resolve,
+    usr_features: &'a ResolvedFeatures,
     std_resolve: Option<&'a Resolve>,
+    std_features: Option<&'a ResolvedFeatures>,
     /// This flag is `true` while generating the dependencies for the standard
     /// library.
     is_std: bool,
@@ -60,10 +65,15 @@ struct State<'a, 'cfg> {
 pub fn build_unit_dependencies<'a, 'cfg>(
     bcx: &'a BuildContext<'a, 'cfg>,
     resolve: &'a Resolve,
-    std_resolve: Option<&'a Resolve>,
+    features: &'a ResolvedFeatures,
+    std_resolve: Option<&'a (Resolve, ResolvedFeatures)>,
     roots: &[Unit<'a>],
     std_roots: &[Unit<'a>],
 ) -> CargoResult<UnitGraph<'a>> {
+    let (std_resolve, std_features) = match std_resolve {
+        Some((r, f)) => (Some(r), Some(f)),
+        None => (None, None),
+    };
     let mut state = State {
         bcx,
         downloads: bcx.packages.enable_download()?,
@@ -71,7 +81,9 @@ pub fn build_unit_dependencies<'a, 'cfg>(
         unit_dependencies: HashMap::new(),
         package_cache: HashMap::new(),
         usr_resolve: resolve,
+        usr_features: features,
         std_resolve,
+        std_features,
         is_std: false,
     };
 
@@ -132,6 +144,7 @@ fn attach_std_deps<'a, 'cfg>(
                 extern_crate_name: unit.pkg.name(),
                 // TODO: Does this `public` make sense?
                 public: true,
+                noprelude: true,
             }));
         }
     }
@@ -161,11 +174,11 @@ fn deps_of_roots<'a, 'cfg>(roots: &[Unit<'a>], mut state: &mut State<'a, 'cfg>)
             // 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()
+                UnitFor::new_test(state.bcx.config)
             } else if unit.target.is_custom_build() {
                 // This normally doesn't happen, except `clean` aggressively
                 // generates all units.
-                UnitFor::new_build()
+                UnitFor::new_build(false)
             } else if unit.target.for_host() {
                 // Proc macro / plugin should never have panic set.
                 UnitFor::new_compiler()
@@ -217,7 +230,7 @@ fn compute_deps<'a, 'cfg>(
     unit_for: UnitFor,
 ) -> CargoResult<Vec<UnitDep<'a>>> {
     if unit.mode.is_run_custom_build() {
-        return compute_deps_custom_build(unit, state);
+        return compute_deps_custom_build(unit, unit_for, state);
     } else if unit.mode.is_doc() {
         // Note: this does not include doc test.
         return compute_deps_doc(unit, state);
@@ -225,7 +238,7 @@ fn compute_deps<'a, 'cfg>(
 
     let bcx = state.bcx;
     let id = unit.pkg.package_id();
-    let deps = state.resolve().deps(id).filter(|&(_id, deps)| {
+    let filtered_deps = state.resolve().deps(id).filter(|&(_id, deps)| {
         assert!(!deps.is_empty());
         deps.iter().any(|dep| {
             // If this target is a build command, then we only want build
@@ -247,7 +260,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.dep_platform_activated(dep, unit.kind) {
+            if !bcx.target_data.dep_platform_activated(dep, unit.kind) {
                 return false;
             }
 
@@ -258,7 +271,7 @@ fn compute_deps<'a, 'cfg>(
     });
 
     let mut ret = Vec::new();
-    for (id, _) in deps {
+    for (id, _) in filtered_deps {
         let pkg = match state.get(id)? {
             Some(pkg) => pkg,
             None => continue,
@@ -268,7 +281,10 @@ fn compute_deps<'a, 'cfg>(
             None => continue,
         };
         let mode = check_or_build_mode(unit.mode, lib);
-        let dep_unit_for = unit_for.with_for_host(lib.for_host());
+        let dep_unit_for = unit_for
+            .with_for_host(lib.for_host())
+            // If it is a custom build script, then it *only* has build dependencies.
+            .with_build_dep(unit.target.is_custom_build());
 
         if bcx.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)?;
@@ -296,7 +312,7 @@ fn compute_deps<'a, 'cfg>(
     if unit.target.is_custom_build() {
         return Ok(ret);
     }
-    ret.extend(dep_build_script(unit, state)?);
+    ret.extend(dep_build_script(unit, unit_for, state)?);
 
     // If this target is a binary, test, example, etc, then it depends on
     // the library of the same package. The call to `resolve.deps` above
@@ -323,7 +339,7 @@ fn compute_deps<'a, 'cfg>(
                     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(&f.as_str())
+                            unit.features.contains(&InternedString::new(f.as_str()))
                         })
                 })
                 .map(|t| {
@@ -350,6 +366,7 @@ fn compute_deps<'a, 'cfg>(
 /// the returned set of units must all be run before `unit` is run.
 fn compute_deps_custom_build<'a, 'cfg>(
     unit: &Unit<'a>,
+    unit_for: UnitFor,
     state: &mut State<'a, 'cfg>,
 ) -> CargoResult<Vec<UnitDep<'a>>> {
     if let Some(links) = unit.pkg.manifest().links() {
@@ -358,6 +375,9 @@ fn compute_deps_custom_build<'a, 'cfg>(
             return Ok(Vec::new());
         }
     }
+    // All dependencies of this unit should use profiles for custom
+    // builds.
+    let script_unit_for = UnitFor::new_build(unit_for.is_for_build_dep());
     // When not overridden, then the dependencies to run a build script are:
     //
     // 1. Compiling the build script itself.
@@ -372,9 +392,7 @@ fn compute_deps_custom_build<'a, 'cfg>(
         unit,
         unit.pkg,
         unit.target,
-        // All dependencies of this unit should use profiles for custom
-        // builds.
-        UnitFor::new_build(),
+        script_unit_for,
         // Build scripts always compiled for the host.
         CompileKind::Host,
         CompileMode::Build,
@@ -393,7 +411,7 @@ fn compute_deps_doc<'a, 'cfg>(
         .deps(unit.pkg.package_id())
         .filter(|&(_id, deps)| {
             deps.iter().any(|dep| match dep.kind() {
-                DepKind::Normal => bcx.dep_platform_activated(dep, unit.kind),
+                DepKind::Normal => bcx.target_data.dep_platform_activated(dep, unit.kind),
                 _ => false,
             })
         });
@@ -441,7 +459,7 @@ fn compute_deps_doc<'a, 'cfg>(
     }
 
     // Be sure to build/run the build script for documented libraries.
-    ret.extend(dep_build_script(unit, state)?);
+    ret.extend(dep_build_script(unit, UnitFor::new_normal(), state)?);
 
     // If we document a binary/example, we need the library available.
     if unit.target.is_bin() || unit.target.is_example() {
@@ -483,6 +501,7 @@ fn maybe_lib<'a>(
 /// build script.
 fn dep_build_script<'a>(
     unit: &Unit<'a>,
+    unit_for: UnitFor,
     state: &State<'a, '_>,
 ) -> CargoResult<Option<UnitDep<'a>>> {
     unit.pkg
@@ -496,12 +515,38 @@ fn dep_build_script<'a>(
                 .bcx
                 .profiles
                 .get_profile_run_custom_build(&unit.profile);
+            // UnitFor::new_build 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
+            // script itself.
+            //
+            // If `is_for_build_dep` here is `false`, that means we are a
+            // build.rs script for a normal dependency and we want to set the
+            // CARGO_FEATURE_* environment variables to the features as a
+            // normal dep.
+            //
+            // If `is_for_build_dep` here is `true`, that means that this
+            // package is being used as a build dependency, and so we only
+            // want to set CARGO_FEATURE_* variables for the build-dependency
+            // side of the graph.
+            //
+            // Keep in mind that the RunCustomBuild unit and the Compile
+            // build.rs unit use the same features. This is because some
+            // people use `cfg!` and `#[cfg]` expressions to check for enabled
+            // features instead of just checking `CARGO_FEATURE_*` at runtime.
+            // In the case with `-Zfeatures=build_dep`, and a shared
+            // dependency has different features enabled for normal vs. build,
+            // then the build.rs script will get compiled twice. I believe it
+            // is not feasible to only build it once because it would break a
+            // large number of scripts (they would think they have the wrong
+            // set of features enabled).
+            let script_unit_for = UnitFor::new_build(unit_for.is_for_build_dep());
             new_unit_dep_with_profile(
                 state,
                 unit,
                 unit.pkg,
                 t,
-                UnitFor::new_build(),
+                script_unit_for,
                 unit.kind,
                 CompileMode::RunCustomBuild,
                 profile,
@@ -543,7 +588,6 @@ fn new_unit_dep<'a>(
         state.bcx.ws.is_member(pkg),
         unit_for,
         mode,
-        state.bcx.build_config.profile_kind.clone(),
     );
     new_unit_dep_with_profile(state, parent, pkg, target, unit_for, kind, mode, profile)
 }
@@ -567,7 +611,11 @@ fn new_unit_dep_with_profile<'a>(
     let public = state
         .resolve()
         .is_public_dep(parent.pkg.package_id(), pkg.package_id());
-    let features = state.resolve().features_sorted(pkg.package_id());
+    let features_for = match unit_for.is_for_build_dep() {
+        true => FeaturesFor::BuildDep,
+        false => FeaturesFor::NormalOrDev,
+    };
+    let features = state.activated_features(pkg.package_id(), features_for);
     let unit = state
         .bcx
         .units
@@ -577,6 +625,7 @@ fn new_unit_dep_with_profile<'a>(
         unit_for,
         extern_crate_name,
         public,
+        noprelude: false,
     })
 }
 
@@ -671,6 +720,19 @@ impl<'a, 'cfg> State<'a, 'cfg> {
         }
     }
 
+    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
+        };
+        features.activated_features(pkg_id, features_for)
+    }
+
     fn get(&mut self, id: PackageId) -> CargoResult<Option<&'a Package>> {
         if let Some(pkg) = self.package_cache.get(&id) {
             return Ok(Some(pkg));