cargo/core/compiler/
unit.rs

1//! Types and impls for [`Unit`].
2
3use crate::core::Package;
4use crate::core::compiler::unit_dependencies::IsArtifact;
5use crate::core::compiler::{CompileKind, CompileMode, CompileTarget, CrateType};
6use crate::core::manifest::{Target, TargetKind};
7use crate::core::profiles::Profile;
8use crate::util::GlobalContext;
9use crate::util::interning::InternedString;
10use std::cell::RefCell;
11use std::collections::{BTreeMap, HashSet};
12use std::fmt;
13use std::hash::{Hash, Hasher};
14use std::ops::Deref;
15use std::rc::Rc;
16
17use super::BuildOutput;
18
19/// All information needed to define a unit.
20///
21/// A unit is an object that has enough information so that cargo knows how to build it.
22/// For example, if your package has dependencies, then every dependency will be built as a library
23/// unit. If your package is a library, then it will be built as a library unit as well, or if it
24/// is a binary with `main.rs`, then a binary will be output. There are also separate unit types
25/// for `test`ing and `check`ing, amongst others.
26///
27/// The unit also holds information about all possible metadata about the package in `pkg`.
28///
29/// A unit needs to know extra information in addition to the type and root source file. For
30/// example, it needs to know the target architecture (OS, chip arch etc.) and it needs to know
31/// whether you want a debug or release build. There is enough information in this struct to figure
32/// all that out.
33#[derive(Clone, PartialOrd, Ord)]
34pub struct Unit {
35    inner: Rc<UnitInner>,
36}
37
38/// Internal fields of `Unit` which `Unit` will dereference to.
39#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
40pub struct UnitInner {
41    /// Information about available targets, which files to include/exclude, etc. Basically stuff in
42    /// `Cargo.toml`.
43    pub pkg: Package,
44    /// Information about the specific target to build, out of the possible targets in `pkg`. Not
45    /// to be confused with *target-triple* (or *target architecture* ...), the target arch for a
46    /// build.
47    pub target: Target,
48    /// The profile contains information about *how* the build should be run, including debug
49    /// level, etc.
50    pub profile: Profile,
51    /// Whether this compilation unit is for the host or target architecture.
52    ///
53    /// For example, when
54    /// cross compiling and using a custom build script, the build script needs to be compiled for
55    /// the host architecture so the host rustc can use it (when compiling to the target
56    /// architecture).
57    pub kind: CompileKind,
58    /// The "mode" this unit is being compiled for. See [`CompileMode`] for more details.
59    pub mode: CompileMode,
60    /// The `cfg` features to enable for this unit.
61    /// This must be sorted.
62    pub features: Vec<InternedString>,
63    /// Extra compiler flags to pass to `rustc` for a given unit.
64    ///
65    /// Although it depends on the caller, in the current Cargo implementation,
66    /// these flags take precedence over those from [`BuildContext::extra_args_for`].
67    ///
68    /// As of now, these flags come from environment variables and configurations.
69    /// See [`TargetInfo.rustflags`] for more on how Cargo collects them.
70    ///
71    /// [`BuildContext::extra_args_for`]: crate::core::compiler::build_context::BuildContext::extra_args_for
72    /// [`TargetInfo.rustflags`]: crate::core::compiler::build_context::TargetInfo::rustflags
73    pub rustflags: Rc<[String]>,
74    /// Extra compiler flags to pass to `rustdoc` for a given unit.
75    ///
76    /// Although it depends on the caller, in the current Cargo implementation,
77    /// these flags take precedence over those from [`BuildContext::extra_args_for`].
78    ///
79    /// As of now, these flags come from environment variables and configurations.
80    /// See [`TargetInfo.rustdocflags`] for more on how Cargo collects them.
81    ///
82    /// [`BuildContext::extra_args_for`]: crate::core::compiler::build_context::BuildContext::extra_args_for
83    /// [`TargetInfo.rustdocflags`]: crate::core::compiler::build_context::TargetInfo::rustdocflags
84    pub rustdocflags: Rc<[String]>,
85    /// Build script override for the given library name.
86    ///
87    /// Any package with a `links` value for the given library name will skip
88    /// running its build script and instead use the given output from the
89    /// config file.
90    pub links_overrides: Rc<BTreeMap<String, BuildOutput>>,
91    // if `true`, the dependency is an artifact dependency, requiring special handling when
92    // calculating output directories, linkage and environment variables provided to builds.
93    pub artifact: IsArtifact,
94    /// Whether this is a standard library unit.
95    pub is_std: bool,
96    /// A hash of all dependencies of this unit.
97    ///
98    /// This is used to keep the `Unit` unique in the situation where two
99    /// otherwise identical units need to link to different dependencies. This
100    /// can happen, for example, when there are shared dependencies that need
101    /// to be built with different features between normal and build
102    /// dependencies. See `rebuild_unit_graph_shared` for more on why this is
103    /// done.
104    ///
105    /// This value initially starts as 0, and then is filled in via a
106    /// second-pass after all the unit dependencies have been computed.
107    pub dep_hash: u64,
108
109    /// This is used for target-dependent feature resolution and is copied from
110    /// [`FeaturesFor::ArtifactDep`], if the enum matches the variant.
111    ///
112    /// [`FeaturesFor::ArtifactDep`]: crate::core::resolver::features::FeaturesFor::ArtifactDep
113    pub artifact_target_for_features: Option<CompileTarget>,
114
115    /// Skip compiling this unit because `--compile-time-deps` flag is set and
116    /// this is not a compile time dependency.
117    ///
118    /// Since dependencies of this unit might be compile time dependencies, we
119    /// set this field instead of completely dropping out this unit from unit graph.
120    pub skip_non_compile_time_dep: bool,
121}
122
123impl UnitInner {
124    /// Returns whether compilation of this unit requires all upstream artifacts
125    /// to be available.
126    ///
127    /// This effectively means that this unit is a synchronization point (if the
128    /// return value is `true`) that all previously pipelined units need to
129    /// finish in their entirety before this one is started.
130    pub fn requires_upstream_objects(&self) -> bool {
131        self.mode.is_any_test() || self.target.kind().requires_upstream_objects()
132    }
133
134    /// Returns whether compilation of this unit could benefit from splitting metadata
135    /// into a .rmeta file.
136    pub fn benefits_from_no_embed_metadata(&self) -> bool {
137        matches!(self.mode, CompileMode::Build)
138            && self.target.kind().benefits_from_no_embed_metadata()
139    }
140
141    /// Returns whether or not this is a "local" package.
142    ///
143    /// A "local" package is one that the user can likely edit, or otherwise
144    /// wants warnings, etc.
145    pub fn is_local(&self) -> bool {
146        self.pkg.package_id().source_id().is_path() && !self.is_std
147    }
148
149    /// Returns whether or not warnings should be displayed for this unit.
150    pub fn show_warnings(&self, gctx: &GlobalContext) -> bool {
151        self.is_local() || gctx.extra_verbose()
152    }
153}
154
155// Just hash the pointer for fast hashing
156impl Hash for Unit {
157    fn hash<H: Hasher>(&self, hasher: &mut H) {
158        std::ptr::hash(&*self.inner, hasher)
159    }
160}
161
162// Just equate the pointer since these are interned
163impl PartialEq for Unit {
164    fn eq(&self, other: &Unit) -> bool {
165        std::ptr::eq(&*self.inner, &*other.inner)
166    }
167}
168
169impl Eq for Unit {}
170
171impl Deref for Unit {
172    type Target = UnitInner;
173
174    fn deref(&self) -> &UnitInner {
175        &*self.inner
176    }
177}
178
179impl fmt::Debug for Unit {
180    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181        f.debug_struct("Unit")
182            .field("pkg", &self.pkg)
183            .field("target", &self.target)
184            .field("profile", &self.profile)
185            .field("kind", &self.kind)
186            .field("mode", &self.mode)
187            .field("features", &self.features)
188            .field("rustflags", &self.rustflags)
189            .field("rustdocflags", &self.rustdocflags)
190            .field("links_overrides", &self.links_overrides)
191            .field("artifact", &self.artifact.is_true())
192            .field(
193                "artifact_target_for_features",
194                &self.artifact_target_for_features,
195            )
196            .field("is_std", &self.is_std)
197            .field("dep_hash", &self.dep_hash)
198            .finish()
199    }
200}
201
202/// A small structure used to "intern" `Unit` values.
203///
204/// A `Unit` is just a thin pointer to an internal `UnitInner`. This is done to
205/// ensure that `Unit` itself is quite small as well as enabling a very
206/// efficient hash/equality implementation for `Unit`. All units are
207/// manufactured through an interner which guarantees that each equivalent value
208/// is only produced once.
209pub struct UnitInterner {
210    state: RefCell<InternerState>,
211}
212
213struct InternerState {
214    cache: HashSet<Rc<UnitInner>>,
215}
216
217impl UnitInterner {
218    /// Creates a new blank interner
219    pub fn new() -> UnitInterner {
220        UnitInterner {
221            state: RefCell::new(InternerState {
222                cache: HashSet::new(),
223            }),
224        }
225    }
226
227    /// Creates a new `unit` from its components. The returned `Unit`'s fields
228    /// will all be equivalent to the provided arguments, although they may not
229    /// be the exact same instance.
230    pub fn intern(
231        &self,
232        pkg: &Package,
233        target: &Target,
234        profile: Profile,
235        kind: CompileKind,
236        mode: CompileMode,
237        features: Vec<InternedString>,
238        rustflags: Rc<[String]>,
239        rustdocflags: Rc<[String]>,
240        links_overrides: Rc<BTreeMap<String, BuildOutput>>,
241        is_std: bool,
242        dep_hash: u64,
243        artifact: IsArtifact,
244        artifact_target_for_features: Option<CompileTarget>,
245        skip_non_compile_time_dep: bool,
246    ) -> Unit {
247        let target = match (is_std, target.kind()) {
248            // This is a horrible hack to support build-std. `libstd` declares
249            // itself with both rlib and dylib. We don't want the dylib for a
250            // few reasons:
251            //
252            // - dylibs don't have a hash in the filename. If you do something
253            //   (like switch rustc versions), it will stomp on the dylib
254            //   file, invalidating the entire cache (because std is a dep of
255            //   everything).
256            // - We don't want to publicize the presence of dylib for the
257            //   standard library.
258            //
259            // At some point in the future, it would be nice to have a
260            // first-class way of overriding or specifying crate-types.
261            (true, TargetKind::Lib(crate_types)) if crate_types.contains(&CrateType::Dylib) => {
262                let mut new_target = Target::clone(target);
263                new_target.set_kind(TargetKind::Lib(vec![CrateType::Rlib]));
264                new_target
265            }
266            _ => target.clone(),
267        };
268        let inner = self.intern_inner(&UnitInner {
269            pkg: pkg.clone(),
270            target,
271            profile,
272            kind,
273            mode,
274            features,
275            rustflags,
276            rustdocflags,
277            links_overrides,
278            is_std,
279            dep_hash,
280            artifact,
281            artifact_target_for_features,
282            skip_non_compile_time_dep,
283        });
284        Unit { inner }
285    }
286
287    fn intern_inner(&self, item: &UnitInner) -> Rc<UnitInner> {
288        let mut me = self.state.borrow_mut();
289        if let Some(item) = me.cache.get(item) {
290            return item.clone();
291        }
292        let item = Rc::new(item.clone());
293        me.cache.insert(item.clone());
294        item
295    }
296}