Skip to main content

cargo/core/
manifest.rs

1use std::borrow::Cow;
2use std::collections::{BTreeMap, HashMap};
3use std::fmt;
4use std::hash::{Hash, Hasher};
5use std::path::{Path, PathBuf};
6use std::rc::Rc;
7use std::sync::Arc;
8
9use anyhow::Context as _;
10use cargo_util_schemas::manifest::RustVersion;
11use cargo_util_schemas::manifest::{Hints, TomlManifest, TomlProfiles};
12use semver::Version;
13use serde::Serialize;
14use serde::ser;
15use url::Url;
16
17use crate::core::compiler::rustdoc::RustdocScrapeExamples;
18use crate::core::compiler::{CompileKind, CrateType};
19use crate::core::resolver::ResolveBehavior;
20use crate::core::{Dependency, PackageId, PackageIdSpec, Patch, SourceId, Summary};
21use crate::core::{Edition, Feature, Features, WorkspaceConfig};
22use crate::util::errors::*;
23use crate::util::interning::InternedString;
24use crate::util::{Filesystem, GlobalContext, short_hash};
25
26pub const MANIFEST_PREAMBLE: &str = "\
27# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
28#
29# When uploading crates to the registry Cargo will automatically
30# \"normalize\" Cargo.toml files for maximal compatibility
31# with all versions of Cargo and also rewrite `path` dependencies
32# to registry (e.g., crates.io) dependencies.
33#
34# If you are reading this file be aware that the original Cargo.toml
35# will likely look very different (and much more reasonable).
36# See Cargo.toml.orig for the original contents.
37";
38
39pub enum EitherManifest {
40    Real(Manifest),
41    Virtual(VirtualManifest),
42}
43
44impl EitherManifest {
45    pub fn warnings_mut(&mut self) -> &mut Warnings {
46        match self {
47            EitherManifest::Real(r) => r.warnings_mut(),
48            EitherManifest::Virtual(v) => v.warnings_mut(),
49        }
50    }
51    pub(crate) fn workspace_config(&self) -> &WorkspaceConfig {
52        match *self {
53            EitherManifest::Real(ref r) => r.workspace_config(),
54            EitherManifest::Virtual(ref v) => v.workspace_config(),
55        }
56    }
57}
58
59/// Contains all the information about a package, as loaded from a `Cargo.toml`.
60///
61/// This is deserialized using the [`TomlManifest`] type.
62#[derive(Clone, Debug)]
63pub struct Manifest {
64    // alternate forms of manifests:
65    contents: Option<Rc<String>>,
66    document: Option<Arc<toml::Spanned<toml::de::DeTable<'static>>>>,
67    original_toml: Option<Rc<TomlManifest>>,
68    normalized_toml: Rc<TomlManifest>,
69    summary: Summary,
70
71    // this form of manifest:
72    targets: Vec<Target>,
73    default_kind: Option<CompileKind>,
74    forced_kind: Option<CompileKind>,
75    links: Option<String>,
76    warnings: Warnings,
77    exclude: Vec<String>,
78    include: Vec<String>,
79    metadata: ManifestMetadata,
80    custom_metadata: Option<toml::Value>,
81    publish: Option<Vec<String>>,
82    replace: Vec<(PackageIdSpec, Dependency)>,
83    patch: HashMap<Url, Vec<Patch>>,
84    workspace: WorkspaceConfig,
85    unstable_features: Features,
86    edition: Edition,
87    rust_version: Option<RustVersion>,
88    im_a_teapot: Option<bool>,
89    default_run: Option<String>,
90    metabuild: Option<Vec<String>>,
91    resolve_behavior: Option<ResolveBehavior>,
92    lint_rustflags: Vec<String>,
93    hints: Option<Hints>,
94    embedded: bool,
95}
96
97/// When parsing `Cargo.toml`, some warnings should silenced
98/// if the manifest comes from a dependency. `ManifestWarning`
99/// allows this delayed emission of warnings.
100#[derive(Clone, Debug)]
101pub struct DelayedWarning {
102    pub message: String,
103    pub is_critical: bool,
104}
105
106#[derive(Clone, Debug)]
107pub struct Warnings(Vec<DelayedWarning>);
108
109#[derive(Clone, Debug)]
110pub struct VirtualManifest {
111    // alternate forms of manifests:
112    contents: Option<Rc<String>>,
113    document: Option<Rc<toml::Spanned<toml::de::DeTable<'static>>>>,
114    original_toml: Option<Rc<TomlManifest>>,
115    normalized_toml: Rc<TomlManifest>,
116
117    // this form of manifest:
118    replace: Vec<(PackageIdSpec, Dependency)>,
119    patch: HashMap<Url, Vec<Patch>>,
120    workspace: WorkspaceConfig,
121    warnings: Warnings,
122    features: Features,
123    resolve_behavior: Option<ResolveBehavior>,
124}
125
126/// General metadata about a package which is just blindly uploaded to the
127/// registry.
128///
129/// Note that many of these fields can contain invalid values such as the
130/// homepage, repository, documentation, or license. These fields are not
131/// validated by cargo itself, but rather it is up to the registry when uploaded
132/// to validate these fields. Cargo will itself accept any valid TOML
133/// specification for these values.
134#[derive(PartialEq, Clone, Debug)]
135pub struct ManifestMetadata {
136    pub authors: Vec<String>,
137    pub keywords: Vec<String>,
138    pub categories: Vec<String>,
139    pub license: Option<String>,
140    pub license_file: Option<String>,
141    pub description: Option<String>,   // Not in Markdown
142    pub readme: Option<String>,        // File, not contents
143    pub homepage: Option<String>,      // URL
144    pub repository: Option<String>,    // URL
145    pub documentation: Option<String>, // URL
146    pub badges: BTreeMap<String, BTreeMap<String, String>>,
147    pub links: Option<String>,
148    pub rust_version: Option<RustVersion>,
149}
150
151impl ManifestMetadata {
152    /// Whether the given env var should be tracked by Cargo's dep-info.
153    pub fn should_track(env_key: &str) -> bool {
154        let keys = MetadataEnvs::keys();
155        keys.contains(&env_key)
156    }
157
158    pub fn env_var<'a>(&'a self, env_key: &str) -> Option<Cow<'a, str>> {
159        MetadataEnvs::var(self, env_key)
160    }
161
162    pub fn env_vars(&self) -> impl Iterator<Item = (&'static str, Cow<'_, str>)> {
163        MetadataEnvs::keys()
164            .iter()
165            .map(|k| (*k, MetadataEnvs::var(self, k).unwrap()))
166    }
167}
168
169macro_rules! get_metadata_env {
170    ($meta:ident, $field:ident) => {
171        $meta.$field.as_deref().unwrap_or_default().into()
172    };
173    ($meta:ident, $field:ident, $to_var:expr) => {
174        $to_var($meta).into()
175    };
176}
177
178struct MetadataEnvs;
179
180macro_rules! metadata_envs {
181    (
182        $(
183            ($field:ident, $key:literal$(, $to_var:expr)?),
184        )*
185    ) => {
186        impl MetadataEnvs {
187            fn keys() -> &'static [&'static str] {
188                &[$($key),*]
189            }
190
191            fn var<'a>(meta: &'a ManifestMetadata, key: &str) -> Option<Cow<'a, str>> {
192                match key {
193                    $($key => Some(get_metadata_env!(meta, $field$(, $to_var)?)),)*
194                    _ => None,
195                }
196            }
197        }
198    }
199}
200
201// Metadata environmental variables that are emitted to rustc. Usable by `env!()`
202// If these change we need to trigger a rebuild.
203// NOTE: The env var name will be prefixed with `CARGO_PKG_`
204metadata_envs! {
205    (description, "CARGO_PKG_DESCRIPTION"),
206    (homepage, "CARGO_PKG_HOMEPAGE"),
207    (repository, "CARGO_PKG_REPOSITORY"),
208    (license, "CARGO_PKG_LICENSE"),
209    (license_file, "CARGO_PKG_LICENSE_FILE"),
210    (authors, "CARGO_PKG_AUTHORS", |m: &ManifestMetadata| m.authors.join(":")),
211    (rust_version, "CARGO_PKG_RUST_VERSION", |m: &ManifestMetadata| m.rust_version.as_ref().map(ToString::to_string).unwrap_or_default()),
212    (readme, "CARGO_PKG_README"),
213}
214
215#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
216pub enum TargetKind {
217    Lib(Vec<CrateType>),
218    Bin,
219    Test,
220    Bench,
221    ExampleLib(Vec<CrateType>),
222    ExampleBin,
223    CustomBuild,
224}
225
226impl ser::Serialize for TargetKind {
227    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
228    where
229        S: ser::Serializer,
230    {
231        use self::TargetKind::*;
232        match self {
233            Lib(kinds) => s.collect_seq(kinds.iter().map(|t| t.to_string())),
234            Bin => ["bin"].serialize(s),
235            ExampleBin | ExampleLib(_) => ["example"].serialize(s),
236            Test => ["test"].serialize(s),
237            CustomBuild => ["custom-build"].serialize(s),
238            Bench => ["bench"].serialize(s),
239        }
240    }
241}
242
243impl fmt::Debug for TargetKind {
244    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
245        use self::TargetKind::*;
246        match *self {
247            Lib(ref kinds) => kinds.fmt(f),
248            Bin => "bin".fmt(f),
249            ExampleBin | ExampleLib(_) => "example".fmt(f),
250            Test => "test".fmt(f),
251            CustomBuild => "custom-build".fmt(f),
252            Bench => "bench".fmt(f),
253        }
254    }
255}
256
257impl TargetKind {
258    pub fn description(&self) -> &'static str {
259        match self {
260            TargetKind::Lib(..) => "lib",
261            TargetKind::Bin => "bin",
262            TargetKind::Test => "integration-test",
263            TargetKind::ExampleBin | TargetKind::ExampleLib(..) => "example",
264            TargetKind::Bench => "bench",
265            TargetKind::CustomBuild => "build-script",
266        }
267    }
268
269    /// Returns whether production of this artifact requires the object files
270    /// from dependencies to be available.
271    ///
272    /// This only returns `false` when all we're producing is an rlib, otherwise
273    /// it will return `true`.
274    pub fn requires_upstream_objects(&self) -> bool {
275        match self {
276            TargetKind::Lib(kinds) | TargetKind::ExampleLib(kinds) => {
277                kinds.iter().any(|k| k.requires_upstream_objects())
278            }
279            _ => true,
280        }
281    }
282
283    /// Returns whether production of this artifact could benefit from splitting metadata
284    /// into a .rmeta file.
285    pub fn benefits_from_no_embed_metadata(&self) -> bool {
286        match self {
287            TargetKind::Lib(kinds) | TargetKind::ExampleLib(kinds) => {
288                kinds.iter().any(|k| k.benefits_from_no_embed_metadata())
289            }
290            _ => false,
291        }
292    }
293
294    /// Returns the arguments suitable for `--crate-type` to pass to rustc.
295    pub fn rustc_crate_types(&self) -> Vec<CrateType> {
296        match self {
297            TargetKind::Lib(kinds) | TargetKind::ExampleLib(kinds) => kinds.clone(),
298            TargetKind::CustomBuild
299            | TargetKind::Bench
300            | TargetKind::Test
301            | TargetKind::ExampleBin
302            | TargetKind::Bin => vec![CrateType::Bin],
303        }
304    }
305}
306
307/// Information about a binary, a library, an example, etc. that is part of the
308/// package.
309#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
310pub struct Target {
311    inner: Arc<TargetInner>,
312}
313
314#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
315struct TargetInner {
316    kind: TargetKind,
317    name: String,
318    // Whether the name was inferred by Cargo, or explicitly given.
319    name_inferred: bool,
320    // Note that `bin_name` is used for the cargo-feature `different_binary_name`
321    bin_name: Option<String>,
322    // Note that the `src_path` here is excluded from the `Hash` implementation
323    // as it's absolute currently and is otherwise a little too brittle for
324    // causing rebuilds. Instead the hash for the path that we send to the
325    // compiler is handled elsewhere.
326    src_path: TargetSourcePath,
327    required_features: Option<Vec<String>>,
328    tested: bool,
329    benched: bool,
330    doc: bool,
331    doctest: bool,
332    harness: bool, // whether to use the test harness (--test)
333    for_host: bool,
334    proc_macro: bool,
335    edition: Edition,
336    doc_scrape_examples: RustdocScrapeExamples,
337}
338
339#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
340pub enum TargetSourcePath {
341    Path(PathBuf),
342    Metabuild,
343}
344
345impl TargetSourcePath {
346    pub fn path(&self) -> Option<&Path> {
347        match self {
348            TargetSourcePath::Path(path) => Some(path.as_ref()),
349            TargetSourcePath::Metabuild => None,
350        }
351    }
352
353    pub fn is_path(&self) -> bool {
354        matches!(self, TargetSourcePath::Path(_))
355    }
356}
357
358impl Hash for TargetSourcePath {
359    fn hash<H: Hasher>(&self, _: &mut H) {
360        // ...
361    }
362}
363
364impl fmt::Debug for TargetSourcePath {
365    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
366        match self {
367            TargetSourcePath::Path(path) => path.fmt(f),
368            TargetSourcePath::Metabuild => "metabuild".fmt(f),
369        }
370    }
371}
372
373impl From<PathBuf> for TargetSourcePath {
374    fn from(path: PathBuf) -> Self {
375        assert!(path.is_absolute(), "`{}` is not absolute", path.display());
376        TargetSourcePath::Path(path)
377    }
378}
379
380#[derive(Serialize)]
381struct SerializedTarget<'a> {
382    /// Is this a `--bin bin`, `--lib`, `--example ex`?
383    /// Serialized as a list of strings for historical reasons.
384    kind: &'a TargetKind,
385    /// Corresponds to `--crate-type` compiler attribute.
386    /// See <https://doc.rust-lang.org/reference/linkage.html>
387    crate_types: Vec<CrateType>,
388    name: &'a str,
389    src_path: Option<&'a PathBuf>,
390    edition: &'a str,
391    #[serde(rename = "required-features", skip_serializing_if = "Option::is_none")]
392    required_features: Option<Vec<&'a str>>,
393    /// Whether docs should be built for the target via `cargo doc`
394    /// See <https://doc.rust-lang.org/cargo/commands/cargo-doc.html#target-selection>
395    doc: bool,
396    doctest: bool,
397    /// Whether tests should be run for the target (`test` field in `Cargo.toml`)
398    test: bool,
399}
400
401impl ser::Serialize for Target {
402    fn serialize<S: ser::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
403        let src_path = match self.src_path() {
404            TargetSourcePath::Path(p) => Some(p),
405            // Unfortunately getting the correct path would require access to
406            // target_dir, which is not available here.
407            TargetSourcePath::Metabuild => None,
408        };
409        SerializedTarget {
410            kind: self.kind(),
411            crate_types: self.rustc_crate_types(),
412            name: self.name(),
413            src_path,
414            edition: &self.edition().to_string(),
415            required_features: self
416                .required_features()
417                .map(|rf| rf.iter().map(|s| s.as_str()).collect()),
418            doc: self.documented(),
419            doctest: self.doctested() && self.doctestable(),
420            test: self.tested(),
421        }
422        .serialize(s)
423    }
424}
425
426impl fmt::Debug for Target {
427    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
428        self.inner.fmt(f)
429    }
430}
431
432compact_debug! {
433    impl fmt::Debug for TargetInner {
434        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
435            let (default, default_name) = {
436                match &self.kind {
437                    TargetKind::Lib(kinds) => {
438                        (
439                            Target::lib_target(
440                                &self.name,
441                                kinds.clone(),
442                                self.src_path.path().unwrap().to_path_buf(),
443                                self.edition,
444                            ).inner,
445                            format!("lib_target({:?}, {:?}, {:?}, {:?})",
446                                    self.name, kinds, self.src_path, self.edition),
447                        )
448                    }
449                    TargetKind::CustomBuild => {
450                        match self.src_path {
451                            TargetSourcePath::Path(ref path) => {
452                                (
453                                    Target::custom_build_target(
454                                        &self.name,
455                                        path.to_path_buf(),
456                                        self.edition,
457                                    ).inner,
458                                    format!("custom_build_target({:?}, {:?}, {:?})",
459                                            self.name, path, self.edition),
460                                )
461                            }
462                            TargetSourcePath::Metabuild => {
463                                (
464                                    Target::metabuild_target(&self.name).inner,
465                                    format!("metabuild_target({:?})", self.name),
466                                )
467                            }
468                        }
469                    }
470                    _ => (
471                        Target::new(self.src_path.clone(), self.edition).inner,
472                        format!("with_path({:?}, {:?})", self.src_path, self.edition),
473                    ),
474                }
475            };
476            [debug_the_fields(
477                kind
478                name
479                name_inferred
480                bin_name
481                src_path
482                required_features
483                tested
484                benched
485                doc
486                doctest
487                harness
488                for_host
489                proc_macro
490                edition
491                doc_scrape_examples
492            )]
493        }
494    }
495}
496
497impl Manifest {
498    pub fn new(
499        contents: Option<Rc<String>>,
500        document: Option<Arc<toml::Spanned<toml::de::DeTable<'static>>>>,
501        original_toml: Option<Rc<TomlManifest>>,
502        normalized_toml: Rc<TomlManifest>,
503        summary: Summary,
504
505        default_kind: Option<CompileKind>,
506        forced_kind: Option<CompileKind>,
507        targets: Vec<Target>,
508        exclude: Vec<String>,
509        include: Vec<String>,
510        links: Option<String>,
511        metadata: ManifestMetadata,
512        custom_metadata: Option<toml::Value>,
513        publish: Option<Vec<String>>,
514        replace: Vec<(PackageIdSpec, Dependency)>,
515        patch: HashMap<Url, Vec<Patch>>,
516        workspace: WorkspaceConfig,
517        unstable_features: Features,
518        edition: Edition,
519        rust_version: Option<RustVersion>,
520        im_a_teapot: Option<bool>,
521        default_run: Option<String>,
522        metabuild: Option<Vec<String>>,
523        resolve_behavior: Option<ResolveBehavior>,
524        lint_rustflags: Vec<String>,
525        hints: Option<Hints>,
526        embedded: bool,
527    ) -> Manifest {
528        Manifest {
529            contents,
530            document,
531            original_toml,
532            normalized_toml,
533            summary,
534
535            default_kind,
536            forced_kind,
537            targets,
538            warnings: Warnings::new(),
539            exclude,
540            include,
541            links,
542            metadata,
543            custom_metadata,
544            publish,
545            replace,
546            patch,
547            workspace,
548            unstable_features,
549            edition,
550            rust_version,
551            im_a_teapot,
552            default_run,
553            metabuild,
554            resolve_behavior,
555            lint_rustflags,
556            hints,
557            embedded,
558        }
559    }
560
561    /// The raw contents of the original TOML
562    pub fn contents(&self) -> Option<&str> {
563        self.contents.as_deref().map(|c| c.as_str())
564    }
565    /// See [`Manifest::normalized_toml`] for what "normalized" means
566    pub fn to_normalized_contents(&self) -> CargoResult<String> {
567        let toml = toml::to_string_pretty(self.normalized_toml())?;
568        Ok(format!("{}\n{}", MANIFEST_PREAMBLE, toml))
569    }
570    /// Collection of spans for the original TOML
571    pub fn document(&self) -> Option<&toml::Spanned<toml::de::DeTable<'static>>> {
572        self.document.as_deref()
573    }
574
575    /// Collection of spans for the original TOML, returned as a cloned Arc.
576    pub fn document_rc(&self) -> Option<Arc<toml::Spanned<toml::de::DeTable<'static>>>> {
577        self.document.clone()
578    }
579
580    /// The [`TomlManifest`] as parsed from [`Manifest::document`]
581    pub fn original_toml(&self) -> Option<&TomlManifest> {
582        self.original_toml.as_deref()
583    }
584    /// The [`TomlManifest`] with all fields expanded
585    ///
586    /// This is the intersection of what fields need resolving for cargo-publish that also are
587    /// useful for the operation of cargo, including
588    /// - workspace inheritance
589    /// - target discovery
590    pub fn normalized_toml(&self) -> &TomlManifest {
591        &self.normalized_toml
592    }
593    pub fn summary(&self) -> &Summary {
594        &self.summary
595    }
596    pub fn summary_mut(&mut self) -> &mut Summary {
597        &mut self.summary
598    }
599
600    pub fn dependencies(&self) -> &[Dependency] {
601        self.summary.dependencies()
602    }
603    pub fn default_kind(&self) -> Option<CompileKind> {
604        self.default_kind
605    }
606    pub fn forced_kind(&self) -> Option<CompileKind> {
607        self.forced_kind
608    }
609    pub fn exclude(&self) -> &[String] {
610        &self.exclude
611    }
612    pub fn include(&self) -> &[String] {
613        &self.include
614    }
615    pub fn metadata(&self) -> &ManifestMetadata {
616        &self.metadata
617    }
618    pub fn name(&self) -> InternedString {
619        self.package_id().name()
620    }
621    pub fn package_id(&self) -> PackageId {
622        self.summary.package_id()
623    }
624    pub fn targets(&self) -> &[Target] {
625        &self.targets
626    }
627    // It is used by cargo-c, please do not remove it
628    pub fn targets_mut(&mut self) -> &mut [Target] {
629        &mut self.targets
630    }
631    pub fn version(&self) -> &Version {
632        self.package_id().version()
633    }
634    pub fn warnings_mut(&mut self) -> &mut Warnings {
635        &mut self.warnings
636    }
637    pub fn warnings(&self) -> &Warnings {
638        &self.warnings
639    }
640    pub fn profiles(&self) -> Option<&TomlProfiles> {
641        self.normalized_toml.profile.as_ref()
642    }
643    pub fn publish(&self) -> &Option<Vec<String>> {
644        &self.publish
645    }
646    pub fn replace(&self) -> &[(PackageIdSpec, Dependency)] {
647        &self.replace
648    }
649    pub fn patch(&self) -> &HashMap<Url, Vec<Patch>> {
650        &self.patch
651    }
652    pub fn links(&self) -> Option<&str> {
653        self.links.as_deref()
654    }
655    pub fn is_embedded(&self) -> bool {
656        self.embedded
657    }
658
659    pub fn workspace_config(&self) -> &WorkspaceConfig {
660        &self.workspace
661    }
662
663    /// Unstable, nightly features that are enabled in this manifest.
664    pub fn unstable_features(&self) -> &Features {
665        &self.unstable_features
666    }
667
668    /// The style of resolver behavior to use, declared with the `resolver` field.
669    ///
670    /// Returns `None` if it is not specified.
671    pub fn resolve_behavior(&self) -> Option<ResolveBehavior> {
672        self.resolve_behavior
673    }
674
675    /// `RUSTFLAGS` from the `[lints]` table
676    pub fn lint_rustflags(&self) -> &[String] {
677        self.lint_rustflags.as_slice()
678    }
679
680    pub fn hints(&self) -> Option<&Hints> {
681        self.hints.as_ref()
682    }
683
684    pub fn map_source(self, to_replace: SourceId, replace_with: SourceId) -> Manifest {
685        Manifest {
686            summary: self.summary.map_source(to_replace, replace_with),
687            ..self
688        }
689    }
690
691    pub fn feature_gate(&self) -> CargoResult<()> {
692        if self.im_a_teapot.is_some() {
693            self.unstable_features
694                .require(Feature::test_dummy_unstable())
695                .with_context(|| {
696                    "the `im-a-teapot` manifest key is unstable and may \
697                     not work properly in England"
698                })?;
699        }
700
701        if self.default_kind.is_some() || self.forced_kind.is_some() {
702            self.unstable_features
703                .require(Feature::per_package_target())
704                .with_context(|| {
705                    "the `package.default-target` and `package.forced-target` \
706                     manifest keys are unstable and may not work properly"
707                })?;
708        }
709
710        Ok(())
711    }
712
713    // Just a helper function to test out `-Z` flags on Cargo
714    pub fn print_teapot(&self, gctx: &GlobalContext) {
715        if let Some(teapot) = self.im_a_teapot {
716            if gctx.cli_unstable().print_im_a_teapot {
717                crate::drop_println!(gctx, "im-a-teapot = {}", teapot);
718            }
719        }
720    }
721
722    pub fn edition(&self) -> Edition {
723        self.edition
724    }
725
726    pub fn rust_version(&self) -> Option<&RustVersion> {
727        self.rust_version.as_ref()
728    }
729
730    pub fn custom_metadata(&self) -> Option<&toml::Value> {
731        self.custom_metadata.as_ref()
732    }
733
734    pub fn default_run(&self) -> Option<&str> {
735        self.default_run.as_deref()
736    }
737
738    pub fn metabuild(&self) -> Option<&Vec<String>> {
739        self.metabuild.as_ref()
740    }
741
742    pub fn metabuild_path(&self, target_dir: Filesystem) -> PathBuf {
743        let hash = short_hash(&self.package_id());
744        target_dir
745            .into_path_unlocked()
746            .join(".metabuild")
747            .join(format!("metabuild-{}-{}.rs", self.name(), hash))
748    }
749}
750
751impl VirtualManifest {
752    pub fn new(
753        contents: Option<Rc<String>>,
754        document: Option<Rc<toml::Spanned<toml::de::DeTable<'static>>>>,
755        original_toml: Option<Rc<TomlManifest>>,
756        normalized_toml: Rc<TomlManifest>,
757        replace: Vec<(PackageIdSpec, Dependency)>,
758        patch: HashMap<Url, Vec<Patch>>,
759        workspace: WorkspaceConfig,
760        features: Features,
761        resolve_behavior: Option<ResolveBehavior>,
762    ) -> VirtualManifest {
763        VirtualManifest {
764            contents,
765            document,
766            original_toml,
767            normalized_toml,
768            replace,
769            patch,
770            workspace,
771            warnings: Warnings::new(),
772            features,
773            resolve_behavior,
774        }
775    }
776
777    /// The raw contents of the original TOML
778    pub fn contents(&self) -> Option<&str> {
779        self.contents.as_deref().map(|c| c.as_str())
780    }
781    /// Collection of spans for the original TOML
782    pub fn document(&self) -> Option<&toml::Spanned<toml::de::DeTable<'static>>> {
783        self.document.as_deref()
784    }
785    /// The [`TomlManifest`] as parsed from [`VirtualManifest::document`]
786    pub fn original_toml(&self) -> Option<&TomlManifest> {
787        self.original_toml.as_deref()
788    }
789    /// The [`TomlManifest`] with all fields expanded
790    pub fn normalized_toml(&self) -> &TomlManifest {
791        &self.normalized_toml
792    }
793
794    pub fn replace(&self) -> &[(PackageIdSpec, Dependency)] {
795        &self.replace
796    }
797
798    pub fn patch(&self) -> &HashMap<Url, Vec<Patch>> {
799        &self.patch
800    }
801
802    pub fn workspace_config(&self) -> &WorkspaceConfig {
803        &self.workspace
804    }
805
806    pub fn profiles(&self) -> Option<&TomlProfiles> {
807        self.normalized_toml.profile.as_ref()
808    }
809
810    pub fn warnings_mut(&mut self) -> &mut Warnings {
811        &mut self.warnings
812    }
813
814    pub fn warnings(&self) -> &Warnings {
815        &self.warnings
816    }
817
818    pub fn unstable_features(&self) -> &Features {
819        &self.features
820    }
821
822    /// The style of resolver behavior to use, declared with the `resolver` field.
823    ///
824    /// Returns `None` if it is not specified.
825    pub fn resolve_behavior(&self) -> Option<ResolveBehavior> {
826        self.resolve_behavior
827    }
828}
829
830impl Target {
831    fn new(src_path: TargetSourcePath, edition: Edition) -> Target {
832        Target {
833            inner: Arc::new(TargetInner {
834                kind: TargetKind::Bin,
835                name: String::new(),
836                name_inferred: false,
837                bin_name: None,
838                src_path,
839                required_features: None,
840                doc: false,
841                doctest: false,
842                harness: true,
843                for_host: false,
844                proc_macro: false,
845                doc_scrape_examples: RustdocScrapeExamples::Unset,
846                edition,
847                tested: true,
848                benched: true,
849            }),
850        }
851    }
852
853    fn with_path(src_path: PathBuf, edition: Edition) -> Target {
854        Target::new(TargetSourcePath::from(src_path), edition)
855    }
856
857    pub fn lib_target(
858        name: &str,
859        crate_targets: Vec<CrateType>,
860        src_path: PathBuf,
861        edition: Edition,
862    ) -> Target {
863        let mut target = Target::with_path(src_path, edition);
864        target
865            .set_kind(TargetKind::Lib(crate_targets))
866            .set_name(name)
867            .set_doctest(true)
868            .set_doc(true);
869        target
870    }
871
872    pub fn bin_target(
873        name: &str,
874        bin_name: Option<String>,
875        src_path: PathBuf,
876        required_features: Option<Vec<String>>,
877        edition: Edition,
878    ) -> Target {
879        let mut target = Target::with_path(src_path, edition);
880        target
881            .set_kind(TargetKind::Bin)
882            .set_name(name)
883            .set_binary_name(bin_name)
884            .set_required_features(required_features)
885            .set_doc(true);
886        target
887    }
888
889    /// Builds a `Target` corresponding to the `build = "build.rs"` entry.
890    pub fn custom_build_target(name: &str, src_path: PathBuf, edition: Edition) -> Target {
891        let mut target = Target::with_path(src_path, edition);
892        target
893            .set_kind(TargetKind::CustomBuild)
894            .set_name(name)
895            .set_for_host(true)
896            .set_benched(false)
897            .set_tested(false)
898            .set_doc_scrape_examples(RustdocScrapeExamples::Disabled);
899        target
900    }
901
902    pub fn metabuild_target(name: &str) -> Target {
903        let mut target = Target::new(TargetSourcePath::Metabuild, Edition::Edition2018);
904        target
905            .set_kind(TargetKind::CustomBuild)
906            .set_name(name)
907            .set_for_host(true)
908            .set_benched(false)
909            .set_tested(false)
910            .set_doc_scrape_examples(RustdocScrapeExamples::Disabled);
911        target
912    }
913
914    pub fn example_target(
915        name: &str,
916        crate_targets: Vec<CrateType>,
917        src_path: PathBuf,
918        required_features: Option<Vec<String>>,
919        edition: Edition,
920    ) -> Target {
921        let kind = if crate_targets.is_empty() || crate_targets.iter().all(|t| *t == CrateType::Bin)
922        {
923            TargetKind::ExampleBin
924        } else {
925            TargetKind::ExampleLib(crate_targets)
926        };
927        let mut target = Target::with_path(src_path, edition);
928        target
929            .set_kind(kind)
930            .set_name(name)
931            .set_required_features(required_features)
932            .set_tested(false)
933            .set_benched(false);
934        target
935    }
936
937    pub fn test_target(
938        name: &str,
939        src_path: PathBuf,
940        required_features: Option<Vec<String>>,
941        edition: Edition,
942    ) -> Target {
943        let mut target = Target::with_path(src_path, edition);
944        target
945            .set_kind(TargetKind::Test)
946            .set_name(name)
947            .set_required_features(required_features)
948            .set_benched(false);
949        target
950    }
951
952    pub fn bench_target(
953        name: &str,
954        src_path: PathBuf,
955        required_features: Option<Vec<String>>,
956        edition: Edition,
957    ) -> Target {
958        let mut target = Target::with_path(src_path, edition);
959        target
960            .set_kind(TargetKind::Bench)
961            .set_name(name)
962            .set_required_features(required_features)
963            .set_tested(false);
964        target
965    }
966
967    pub fn name(&self) -> &str {
968        &self.inner.name
969    }
970    pub fn name_inferred(&self) -> bool {
971        self.inner.name_inferred
972    }
973    pub fn crate_name(&self) -> String {
974        self.name().replace("-", "_")
975    }
976    pub fn src_path(&self) -> &TargetSourcePath {
977        &self.inner.src_path
978    }
979    pub fn set_src_path(&mut self, src_path: TargetSourcePath) {
980        Arc::make_mut(&mut self.inner).src_path = src_path;
981    }
982    pub fn required_features(&self) -> Option<&Vec<String>> {
983        self.inner.required_features.as_ref()
984    }
985    pub fn kind(&self) -> &TargetKind {
986        &self.inner.kind
987    }
988    pub fn tested(&self) -> bool {
989        self.inner.tested
990    }
991    pub fn harness(&self) -> bool {
992        self.inner.harness
993    }
994    pub fn documented(&self) -> bool {
995        self.inner.doc
996    }
997    // A proc-macro or build-script.
998    pub fn for_host(&self) -> bool {
999        self.inner.for_host
1000    }
1001    pub fn proc_macro(&self) -> bool {
1002        self.inner.proc_macro
1003    }
1004    pub fn edition(&self) -> Edition {
1005        self.inner.edition
1006    }
1007    pub fn doc_scrape_examples(&self) -> RustdocScrapeExamples {
1008        self.inner.doc_scrape_examples
1009    }
1010    pub fn benched(&self) -> bool {
1011        self.inner.benched
1012    }
1013    pub fn doctested(&self) -> bool {
1014        self.inner.doctest
1015    }
1016
1017    pub fn doctestable(&self) -> bool {
1018        match self.kind() {
1019            TargetKind::Lib(kinds) => kinds.iter().any(|k| {
1020                *k == CrateType::Rlib || *k == CrateType::Lib || *k == CrateType::ProcMacro
1021            }),
1022            _ => false,
1023        }
1024    }
1025
1026    pub fn is_lib(&self) -> bool {
1027        matches!(self.kind(), TargetKind::Lib(_))
1028    }
1029
1030    pub fn is_dylib(&self) -> bool {
1031        match self.kind() {
1032            TargetKind::Lib(libs) => libs.contains(&CrateType::Dylib),
1033            _ => false,
1034        }
1035    }
1036
1037    pub fn is_cdylib(&self) -> bool {
1038        match self.kind() {
1039            TargetKind::Lib(libs) => libs.contains(&CrateType::Cdylib),
1040            _ => false,
1041        }
1042    }
1043
1044    pub fn is_staticlib(&self) -> bool {
1045        match self.kind() {
1046            TargetKind::Lib(libs) => libs.contains(&CrateType::Staticlib),
1047            _ => false,
1048        }
1049    }
1050
1051    /// Returns whether this target produces an artifact which can be linked
1052    /// into a Rust crate.
1053    ///
1054    /// This only returns true for certain kinds of libraries.
1055    pub fn is_linkable(&self) -> bool {
1056        match self.kind() {
1057            TargetKind::Lib(kinds) => kinds.iter().any(|k| k.is_linkable()),
1058            _ => false,
1059        }
1060    }
1061
1062    pub fn is_bin(&self) -> bool {
1063        *self.kind() == TargetKind::Bin
1064    }
1065
1066    pub fn is_example(&self) -> bool {
1067        matches!(
1068            self.kind(),
1069            TargetKind::ExampleBin | TargetKind::ExampleLib(..)
1070        )
1071    }
1072
1073    /// Returns `true` if it is a binary or executable example.
1074    /// NOTE: Tests are `false`!
1075    pub fn is_executable(&self) -> bool {
1076        self.is_bin() || self.is_exe_example()
1077    }
1078
1079    /// Returns `true` if it is an executable example.
1080    pub fn is_exe_example(&self) -> bool {
1081        // Needed for --all-examples in contexts where only runnable examples make sense
1082        matches!(self.kind(), TargetKind::ExampleBin)
1083    }
1084
1085    pub fn is_test(&self) -> bool {
1086        *self.kind() == TargetKind::Test
1087    }
1088    pub fn is_bench(&self) -> bool {
1089        *self.kind() == TargetKind::Bench
1090    }
1091    pub fn is_custom_build(&self) -> bool {
1092        *self.kind() == TargetKind::CustomBuild
1093    }
1094
1095    /// Returns `true` if it is a compile time dependencies, e.g., build script or proc macro
1096    pub fn is_compile_time_dependency(&self) -> bool {
1097        self.is_custom_build() || self.proc_macro()
1098    }
1099
1100    /// Returns the arguments suitable for `--crate-type` to pass to rustc.
1101    pub fn rustc_crate_types(&self) -> Vec<CrateType> {
1102        self.kind().rustc_crate_types()
1103    }
1104
1105    pub fn set_tested(&mut self, tested: bool) -> &mut Target {
1106        Arc::make_mut(&mut self.inner).tested = tested;
1107        self
1108    }
1109    pub fn set_benched(&mut self, benched: bool) -> &mut Target {
1110        Arc::make_mut(&mut self.inner).benched = benched;
1111        self
1112    }
1113    pub fn set_doctest(&mut self, doctest: bool) -> &mut Target {
1114        Arc::make_mut(&mut self.inner).doctest = doctest;
1115        self
1116    }
1117    pub fn set_for_host(&mut self, for_host: bool) -> &mut Target {
1118        Arc::make_mut(&mut self.inner).for_host = for_host;
1119        self
1120    }
1121    pub fn set_proc_macro(&mut self, proc_macro: bool) -> &mut Target {
1122        Arc::make_mut(&mut self.inner).proc_macro = proc_macro;
1123        self
1124    }
1125    pub fn set_edition(&mut self, edition: Edition) -> &mut Target {
1126        Arc::make_mut(&mut self.inner).edition = edition;
1127        self
1128    }
1129    pub fn set_doc_scrape_examples(
1130        &mut self,
1131        doc_scrape_examples: RustdocScrapeExamples,
1132    ) -> &mut Target {
1133        Arc::make_mut(&mut self.inner).doc_scrape_examples = doc_scrape_examples;
1134        self
1135    }
1136    pub fn set_harness(&mut self, harness: bool) -> &mut Target {
1137        Arc::make_mut(&mut self.inner).harness = harness;
1138        self
1139    }
1140    pub fn set_doc(&mut self, doc: bool) -> &mut Target {
1141        Arc::make_mut(&mut self.inner).doc = doc;
1142        self
1143    }
1144    pub fn set_kind(&mut self, kind: TargetKind) -> &mut Target {
1145        Arc::make_mut(&mut self.inner).kind = kind;
1146        self
1147    }
1148    pub fn set_name(&mut self, name: &str) -> &mut Target {
1149        Arc::make_mut(&mut self.inner).name = name.to_string();
1150        self
1151    }
1152    pub fn set_name_inferred(&mut self, inferred: bool) -> &mut Target {
1153        Arc::make_mut(&mut self.inner).name_inferred = inferred;
1154        self
1155    }
1156    pub fn set_binary_name(&mut self, bin_name: Option<String>) -> &mut Target {
1157        Arc::make_mut(&mut self.inner).bin_name = bin_name;
1158        self
1159    }
1160    pub fn set_required_features(&mut self, required_features: Option<Vec<String>>) -> &mut Target {
1161        Arc::make_mut(&mut self.inner).required_features = required_features;
1162        self
1163    }
1164    pub fn binary_filename(&self) -> Option<String> {
1165        self.inner.bin_name.clone()
1166    }
1167    pub fn description_named(&self) -> String {
1168        match self.kind() {
1169            TargetKind::Lib(..) => "lib".to_string(),
1170            TargetKind::Bin => format!("bin \"{}\"", self.name()),
1171            TargetKind::Test => format!("test \"{}\"", self.name()),
1172            TargetKind::Bench => format!("bench \"{}\"", self.name()),
1173            TargetKind::ExampleLib(..) | TargetKind::ExampleBin => {
1174                format!("example \"{}\"", self.name())
1175            }
1176            TargetKind::CustomBuild => "build script".to_string(),
1177        }
1178    }
1179}
1180
1181impl fmt::Display for Target {
1182    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1183        match self.kind() {
1184            TargetKind::Lib(..) => write!(f, "Target(lib)"),
1185            TargetKind::Bin => write!(f, "Target(bin: {})", self.name()),
1186            TargetKind::Test => write!(f, "Target(test: {})", self.name()),
1187            TargetKind::Bench => write!(f, "Target(bench: {})", self.name()),
1188            TargetKind::ExampleBin | TargetKind::ExampleLib(..) => {
1189                write!(f, "Target(example: {})", self.name())
1190            }
1191            TargetKind::CustomBuild => write!(f, "Target(script)"),
1192        }
1193    }
1194}
1195
1196impl Warnings {
1197    fn new() -> Warnings {
1198        Warnings(Vec::new())
1199    }
1200
1201    pub fn add_warning(&mut self, s: String) {
1202        self.0.push(DelayedWarning {
1203            message: s,
1204            is_critical: false,
1205        })
1206    }
1207
1208    pub fn add_critical_warning(&mut self, s: String) {
1209        self.0.push(DelayedWarning {
1210            message: s,
1211            is_critical: true,
1212        })
1213    }
1214
1215    pub fn warnings(&self) -> &[DelayedWarning] {
1216        &self.0
1217    }
1218}