#
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, 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: Rc<String>,
    66    document: Rc<toml::Spanned<toml::de::DeTable<'static>>>,
    67    original_toml: 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<Dependency>>,
    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: Rc<String>,
    113    document: Rc<toml::Spanned<toml::de::DeTable<'static>>>,
    114    original_toml: Rc<TomlManifest>,
    115    normalized_toml: Rc<TomlManifest>,
    116
    117    // this form of manifest:
    118    replace: Vec<(PackageIdSpec, Dependency)>,
    119    patch: HashMap<Url, Vec<Dependency>>,
    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: Rc<String>,
    500        document: Rc<toml::Spanned<toml::de::DeTable<'static>>>,
    501        original_toml: 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<Dependency>>,
    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) -> &str {
    563        self.contents.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) -> &toml::Spanned<toml::de::DeTable<'static>> {
    572        &self.document
    573    }
    574    /// The [`TomlManifest`] as parsed from [`Manifest::document`]
    575    pub fn original_toml(&self) -> &TomlManifest {
    576        &self.original_toml
    577    }
    578    /// The [`TomlManifest`] with all fields expanded
    579    ///
    580    /// This is the intersection of what fields need resolving for cargo-publish that also are
    581    /// useful for the operation of cargo, including
    582    /// - workspace inheritance
    583    /// - target discovery
    584    pub fn normalized_toml(&self) -> &TomlManifest {
    585        &self.normalized_toml
    586    }
    587    pub fn summary(&self) -> &Summary {
    588        &self.summary
    589    }
    590    pub fn summary_mut(&mut self) -> &mut Summary {
    591        &mut self.summary
    592    }
    593
    594    pub fn dependencies(&self) -> &[Dependency] {
    595        self.summary.dependencies()
    596    }
    597    pub fn default_kind(&self) -> Option<CompileKind> {
    598        self.default_kind
    599    }
    600    pub fn forced_kind(&self) -> Option<CompileKind> {
    601        self.forced_kind
    602    }
    603    pub fn exclude(&self) -> &[String] {
    604        &self.exclude
    605    }
    606    pub fn include(&self) -> &[String] {
    607        &self.include
    608    }
    609    pub fn metadata(&self) -> &ManifestMetadata {
    610        &self.metadata
    611    }
    612    pub fn name(&self) -> InternedString {
    613        self.package_id().name()
    614    }
    615    pub fn package_id(&self) -> PackageId {
    616        self.summary.package_id()
    617    }
    618    pub fn targets(&self) -> &[Target] {
    619        &self.targets
    620    }
    621    // It is used by cargo-c, please do not remove it
    622    pub fn targets_mut(&mut self) -> &mut [Target] {
    623        &mut self.targets
    624    }
    625    pub fn version(&self) -> &Version {
    626        self.package_id().version()
    627    }
    628    pub fn warnings_mut(&mut self) -> &mut Warnings {
    629        &mut self.warnings
    630    }
    631    pub fn warnings(&self) -> &Warnings {
    632        &self.warnings
    633    }
    634    pub fn profiles(&self) -> Option<&TomlProfiles> {
    635        self.normalized_toml.profile.as_ref()
    636    }
    637    pub fn publish(&self) -> &Option<Vec<String>> {
    638        &self.publish
    639    }
    640    pub fn replace(&self) -> &[(PackageIdSpec, Dependency)] {
    641        &self.replace
    642    }
    643    pub fn patch(&self) -> &HashMap<Url, Vec<Dependency>> {
    644        &self.patch
    645    }
    646    pub fn links(&self) -> Option<&str> {
    647        self.links.as_deref()
    648    }
    649    pub fn is_embedded(&self) -> bool {
    650        self.embedded
    651    }
    652
    653    pub fn workspace_config(&self) -> &WorkspaceConfig {
    654        &self.workspace
    655    }
    656
    657    /// Unstable, nightly features that are enabled in this manifest.
    658    pub fn unstable_features(&self) -> &Features {
    659        &self.unstable_features
    660    }
    661
    662    /// The style of resolver behavior to use, declared with the `resolver` field.
    663    ///
    664    /// Returns `None` if it is not specified.
    665    pub fn resolve_behavior(&self) -> Option<ResolveBehavior> {
    666        self.resolve_behavior
    667    }
    668
    669    /// `RUSTFLAGS` from the `[lints]` table
    670    pub fn lint_rustflags(&self) -> &[String] {
    671        self.lint_rustflags.as_slice()
    672    }
    673
    674    pub fn hints(&self) -> Option<&Hints> {
    675        self.hints.as_ref()
    676    }
    677
    678    pub fn map_source(self, to_replace: SourceId, replace_with: SourceId) -> Manifest {
    679        Manifest {
    680            summary: self.summary.map_source(to_replace, replace_with),
    681            ..self
    682        }
    683    }
    684
    685    pub fn feature_gate(&self) -> CargoResult<()> {
    686        if self.im_a_teapot.is_some() {
    687            self.unstable_features
    688                .require(Feature::test_dummy_unstable())
    689                .with_context(|| {
    690                    "the `im-a-teapot` manifest key is unstable and may \
    691                     not work properly in England"
    692                })?;
    693        }
    694
    695        if self.default_kind.is_some() || self.forced_kind.is_some() {
    696            self.unstable_features
    697                .require(Feature::per_package_target())
    698                .with_context(|| {
    699                    "the `package.default-target` and `package.forced-target` \
    700                     manifest keys are unstable and may not work properly"
    701                })?;
    702        }
    703
    704        Ok(())
    705    }
    706
    707    // Just a helper function to test out `-Z` flags on Cargo
    708    pub fn print_teapot(&self, gctx: &GlobalContext) {
    709        if let Some(teapot) = self.im_a_teapot {
    710            if gctx.cli_unstable().print_im_a_teapot {
    711                crate::drop_println!(gctx, "im-a-teapot = {}", teapot);
    712            }
    713        }
    714    }
    715
    716    pub fn edition(&self) -> Edition {
    717        self.edition
    718    }
    719
    720    pub fn rust_version(&self) -> Option<&RustVersion> {
    721        self.rust_version.as_ref()
    722    }
    723
    724    pub fn custom_metadata(&self) -> Option<&toml::Value> {
    725        self.custom_metadata.as_ref()
    726    }
    727
    728    pub fn default_run(&self) -> Option<&str> {
    729        self.default_run.as_deref()
    730    }
    731
    732    pub fn metabuild(&self) -> Option<&Vec<String>> {
    733        self.metabuild.as_ref()
    734    }
    735
    736    pub fn metabuild_path(&self, target_dir: Filesystem) -> PathBuf {
    737        let hash = short_hash(&self.package_id());
    738        target_dir
    739            .into_path_unlocked()
    740            .join(".metabuild")
    741            .join(format!("metabuild-{}-{}.rs", self.name(), hash))
    742    }
    743}
    744
    745impl VirtualManifest {
    746    pub fn new(
    747        contents: Rc<String>,
    748        document: Rc<toml::Spanned<toml::de::DeTable<'static>>>,
    749        original_toml: Rc<TomlManifest>,
    750        normalized_toml: Rc<TomlManifest>,
    751        replace: Vec<(PackageIdSpec, Dependency)>,
    752        patch: HashMap<Url, Vec<Dependency>>,
    753        workspace: WorkspaceConfig,
    754        features: Features,
    755        resolve_behavior: Option<ResolveBehavior>,
    756    ) -> VirtualManifest {
    757        VirtualManifest {
    758            contents,
    759            document,
    760            original_toml,
    761            normalized_toml,
    762            replace,
    763            patch,
    764            workspace,
    765            warnings: Warnings::new(),
    766            features,
    767            resolve_behavior,
    768        }
    769    }
    770
    771    /// The raw contents of the original TOML
    772    pub fn contents(&self) -> &str {
    773        self.contents.as_str()
    774    }
    775    /// Collection of spans for the original TOML
    776    pub fn document(&self) -> &toml::Spanned<toml::de::DeTable<'static>> {
    777        &self.document
    778    }
    779    /// The [`TomlManifest`] as parsed from [`VirtualManifest::document`]
    780    pub fn original_toml(&self) -> &TomlManifest {
    781        &self.original_toml
    782    }
    783    /// The [`TomlManifest`] with all fields expanded
    784    pub fn normalized_toml(&self) -> &TomlManifest {
    785        &self.normalized_toml
    786    }
    787
    788    pub fn replace(&self) -> &[(PackageIdSpec, Dependency)] {
    789        &self.replace
    790    }
    791
    792    pub fn patch(&self) -> &HashMap<Url, Vec<Dependency>> {
    793        &self.patch
    794    }
    795
    796    pub fn workspace_config(&self) -> &WorkspaceConfig {
    797        &self.workspace
    798    }
    799
    800    pub fn profiles(&self) -> Option<&TomlProfiles> {
    801        self.normalized_toml.profile.as_ref()
    802    }
    803
    804    pub fn warnings_mut(&mut self) -> &mut Warnings {
    805        &mut self.warnings
    806    }
    807
    808    pub fn warnings(&self) -> &Warnings {
    809        &self.warnings
    810    }
    811
    812    pub fn unstable_features(&self) -> &Features {
    813        &self.features
    814    }
    815
    816    /// The style of resolver behavior to use, declared with the `resolver` field.
    817    ///
    818    /// Returns `None` if it is not specified.
    819    pub fn resolve_behavior(&self) -> Option<ResolveBehavior> {
    820        self.resolve_behavior
    821    }
    822}
    823
    824impl Target {
    825    fn new(src_path: TargetSourcePath, edition: Edition) -> Target {
    826        Target {
    827            inner: Arc::new(TargetInner {
    828                kind: TargetKind::Bin,
    829                name: String::new(),
    830                name_inferred: false,
    831                bin_name: None,
    832                src_path,
    833                required_features: None,
    834                doc: false,
    835                doctest: false,
    836                harness: true,
    837                for_host: false,
    838                proc_macro: false,
    839                doc_scrape_examples: RustdocScrapeExamples::Unset,
    840                edition,
    841                tested: true,
    842                benched: true,
    843            }),
    844        }
    845    }
    846
    847    fn with_path(src_path: PathBuf, edition: Edition) -> Target {
    848        Target::new(TargetSourcePath::from(src_path), edition)
    849    }
    850
    851    pub fn lib_target(
    852        name: &str,
    853        crate_targets: Vec<CrateType>,
    854        src_path: PathBuf,
    855        edition: Edition,
    856    ) -> Target {
    857        let mut target = Target::with_path(src_path, edition);
    858        target
    859            .set_kind(TargetKind::Lib(crate_targets))
    860            .set_name(name)
    861            .set_doctest(true)
    862            .set_doc(true);
    863        target
    864    }
    865
    866    pub fn bin_target(
    867        name: &str,
    868        bin_name: Option<String>,
    869        src_path: PathBuf,
    870        required_features: Option<Vec<String>>,
    871        edition: Edition,
    872    ) -> Target {
    873        let mut target = Target::with_path(src_path, edition);
    874        target
    875            .set_kind(TargetKind::Bin)
    876            .set_name(name)
    877            .set_binary_name(bin_name)
    878            .set_required_features(required_features)
    879            .set_doc(true);
    880        target
    881    }
    882
    883    /// Builds a `Target` corresponding to the `build = "build.rs"` entry.
    884    pub fn custom_build_target(name: &str, src_path: PathBuf, edition: Edition) -> Target {
    885        let mut target = Target::with_path(src_path, edition);
    886        target
    887            .set_kind(TargetKind::CustomBuild)
    888            .set_name(name)
    889            .set_for_host(true)
    890            .set_benched(false)
    891            .set_tested(false)
    892            .set_doc_scrape_examples(RustdocScrapeExamples::Disabled);
    893        target
    894    }
    895
    896    pub fn metabuild_target(name: &str) -> Target {
    897        let mut target = Target::new(TargetSourcePath::Metabuild, Edition::Edition2018);
    898        target
    899            .set_kind(TargetKind::CustomBuild)
    900            .set_name(name)
    901            .set_for_host(true)
    902            .set_benched(false)
    903            .set_tested(false)
    904            .set_doc_scrape_examples(RustdocScrapeExamples::Disabled);
    905        target
    906    }
    907
    908    pub fn example_target(
    909        name: &str,
    910        crate_targets: Vec<CrateType>,
    911        src_path: PathBuf,
    912        required_features: Option<Vec<String>>,
    913        edition: Edition,
    914    ) -> Target {
    915        let kind = if crate_targets.is_empty() || crate_targets.iter().all(|t| *t == CrateType::Bin)
    916        {
    917            TargetKind::ExampleBin
    918        } else {
    919            TargetKind::ExampleLib(crate_targets)
    920        };
    921        let mut target = Target::with_path(src_path, edition);
    922        target
    923            .set_kind(kind)
    924            .set_name(name)
    925            .set_required_features(required_features)
    926            .set_tested(false)
    927            .set_benched(false);
    928        target
    929    }
    930
    931    pub fn test_target(
    932        name: &str,
    933        src_path: PathBuf,
    934        required_features: Option<Vec<String>>,
    935        edition: Edition,
    936    ) -> Target {
    937        let mut target = Target::with_path(src_path, edition);
    938        target
    939            .set_kind(TargetKind::Test)
    940            .set_name(name)
    941            .set_required_features(required_features)
    942            .set_benched(false);
    943        target
    944    }
    945
    946    pub fn bench_target(
    947        name: &str,
    948        src_path: PathBuf,
    949        required_features: Option<Vec<String>>,
    950        edition: Edition,
    951    ) -> Target {
    952        let mut target = Target::with_path(src_path, edition);
    953        target
    954            .set_kind(TargetKind::Bench)
    955            .set_name(name)
    956            .set_required_features(required_features)
    957            .set_tested(false);
    958        target
    959    }
    960
    961    pub fn name(&self) -> &str {
    962        &self.inner.name
    963    }
    964    pub fn name_inferred(&self) -> bool {
    965        self.inner.name_inferred
    966    }
    967    pub fn crate_name(&self) -> String {
    968        self.name().replace("-", "_")
    969    }
    970    pub fn src_path(&self) -> &TargetSourcePath {
    971        &self.inner.src_path
    972    }
    973    pub fn set_src_path(&mut self, src_path: TargetSourcePath) {
    974        Arc::make_mut(&mut self.inner).src_path = src_path;
    975    }
    976    pub fn required_features(&self) -> Option<&Vec<String>> {
    977        self.inner.required_features.as_ref()
    978    }
    979    pub fn kind(&self) -> &TargetKind {
    980        &self.inner.kind
    981    }
    982    pub fn tested(&self) -> bool {
    983        self.inner.tested
    984    }
    985    pub fn harness(&self) -> bool {
    986        self.inner.harness
    987    }
    988    pub fn documented(&self) -> bool {
    989        self.inner.doc
    990    }
    991    // A proc-macro or build-script.
    992    pub fn for_host(&self) -> bool {
    993        self.inner.for_host
    994    }
    995    pub fn proc_macro(&self) -> bool {
    996        self.inner.proc_macro
    997    }
    998    pub fn edition(&self) -> Edition {
    999        self.inner.edition
    1000    }
    1001    pub fn doc_scrape_examples(&self) -> RustdocScrapeExamples {
    1002        self.inner.doc_scrape_examples
    1003    }
    1004    pub fn benched(&self) -> bool {
    1005        self.inner.benched
    1006    }
    1007    pub fn doctested(&self) -> bool {
    1008        self.inner.doctest
    1009    }
    1010
    1011    pub fn doctestable(&self) -> bool {
    1012        match self.kind() {
    1013            TargetKind::Lib(kinds) => kinds.iter().any(|k| {
    1014                *k == CrateType::Rlib || *k == CrateType::Lib || *k == CrateType::ProcMacro
    1015            }),
    1016            _ => false,
    1017        }
    1018    }
    1019
    1020    pub fn is_lib(&self) -> bool {
    1021        matches!(self.kind(), TargetKind::Lib(_))
    1022    }
    1023
    1024    pub fn is_dylib(&self) -> bool {
    1025        match self.kind() {
    1026            TargetKind::Lib(libs) => libs.contains(&CrateType::Dylib),
    1027            _ => false,
    1028        }
    1029    }
    1030
    1031    pub fn is_cdylib(&self) -> bool {
    1032        match self.kind() {
    1033            TargetKind::Lib(libs) => libs.contains(&CrateType::Cdylib),
    1034            _ => false,
    1035        }
    1036    }
    1037
    1038    pub fn is_staticlib(&self) -> bool {
    1039        match self.kind() {
    1040            TargetKind::Lib(libs) => libs.contains(&CrateType::Staticlib),
    1041            _ => false,
    1042        }
    1043    }
    1044
    1045    /// Returns whether this target produces an artifact which can be linked
    1046    /// into a Rust crate.
    1047    ///
    1048    /// This only returns true for certain kinds of libraries.
    1049    pub fn is_linkable(&self) -> bool {
    1050        match self.kind() {
    1051            TargetKind::Lib(kinds) => kinds.iter().any(|k| k.is_linkable()),
    1052            _ => false,
    1053        }
    1054    }
    1055
    1056    pub fn is_bin(&self) -> bool {
    1057        *self.kind() == TargetKind::Bin
    1058    }
    1059
    1060    pub fn is_example(&self) -> bool {
    1061        matches!(
    1062            self.kind(),
    1063            TargetKind::ExampleBin | TargetKind::ExampleLib(..)
    1064        )
    1065    }
    1066
    1067    /// Returns `true` if it is a binary or executable example.
    1068    /// NOTE: Tests are `false`!
    1069    pub fn is_executable(&self) -> bool {
    1070        self.is_bin() || self.is_exe_example()
    1071    }
    1072
    1073    /// Returns `true` if it is an executable example.
    1074    pub fn is_exe_example(&self) -> bool {
    1075        // Needed for --all-examples in contexts where only runnable examples make sense
    1076        matches!(self.kind(), TargetKind::ExampleBin)
    1077    }
    1078
    1079    pub fn is_test(&self) -> bool {
    1080        *self.kind() == TargetKind::Test
    1081    }
    1082    pub fn is_bench(&self) -> bool {
    1083        *self.kind() == TargetKind::Bench
    1084    }
    1085    pub fn is_custom_build(&self) -> bool {
    1086        *self.kind() == TargetKind::CustomBuild
    1087    }
    1088
    1089    /// Returns `true` if it is a compile time dependencies, e.g., build script or proc macro
    1090    pub fn is_compile_time_dependency(&self) -> bool {
    1091        self.is_custom_build() || self.proc_macro()
    1092    }
    1093
    1094    /// Returns the arguments suitable for `--crate-type` to pass to rustc.
    1095    pub fn rustc_crate_types(&self) -> Vec<CrateType> {
    1096        self.kind().rustc_crate_types()
    1097    }
    1098
    1099    pub fn set_tested(&mut self, tested: bool) -> &mut Target {
    1100        Arc::make_mut(&mut self.inner).tested = tested;
    1101        self
    1102    }
    1103    pub fn set_benched(&mut self, benched: bool) -> &mut Target {
    1104        Arc::make_mut(&mut self.inner).benched = benched;
    1105        self
    1106    }
    1107    pub fn set_doctest(&mut self, doctest: bool) -> &mut Target {
    1108        Arc::make_mut(&mut self.inner).doctest = doctest;
    1109        self
    1110    }
    1111    pub fn set_for_host(&mut self, for_host: bool) -> &mut Target {
    1112        Arc::make_mut(&mut self.inner).for_host = for_host;
    1113        self
    1114    }
    1115    pub fn set_proc_macro(&mut self, proc_macro: bool) -> &mut Target {
    1116        Arc::make_mut(&mut self.inner).proc_macro = proc_macro;
    1117        self
    1118    }
    1119    pub fn set_edition(&mut self, edition: Edition) -> &mut Target {
    1120        Arc::make_mut(&mut self.inner).edition = edition;
    1121        self
    1122    }
    1123    pub fn set_doc_scrape_examples(
    1124        &mut self,
    1125        doc_scrape_examples: RustdocScrapeExamples,
    1126    ) -> &mut Target {
    1127        Arc::make_mut(&mut self.inner).doc_scrape_examples = doc_scrape_examples;
    1128        self
    1129    }
    1130    pub fn set_harness(&mut self, harness: bool) -> &mut Target {
    1131        Arc::make_mut(&mut self.inner).harness = harness;
    1132        self
    1133    }
    1134    pub fn set_doc(&mut self, doc: bool) -> &mut Target {
    1135        Arc::make_mut(&mut self.inner).doc = doc;
    1136        self
    1137    }
    1138    pub fn set_kind(&mut self, kind: TargetKind) -> &mut Target {
    1139        Arc::make_mut(&mut self.inner).kind = kind;
    1140        self
    1141    }
    1142    pub fn set_name(&mut self, name: &str) -> &mut Target {
    1143        Arc::make_mut(&mut self.inner).name = name.to_string();
    1144        self
    1145    }
    1146    pub fn set_name_inferred(&mut self, inferred: bool) -> &mut Target {
    1147        Arc::make_mut(&mut self.inner).name_inferred = inferred;
    1148        self
    1149    }
    1150    pub fn set_binary_name(&mut self, bin_name: Option<String>) -> &mut Target {
    1151        Arc::make_mut(&mut self.inner).bin_name = bin_name;
    1152        self
    1153    }
    1154    pub fn set_required_features(&mut self, required_features: Option<Vec<String>>) -> &mut Target {
    1155        Arc::make_mut(&mut self.inner).required_features = required_features;
    1156        self
    1157    }
    1158    pub fn binary_filename(&self) -> Option<String> {
    1159        self.inner.bin_name.clone()
    1160    }
    1161    pub fn description_named(&self) -> String {
    1162        match self.kind() {
    1163            TargetKind::Lib(..) => "lib".to_string(),
    1164            TargetKind::Bin => format!("bin \"{}\"", self.name()),
    1165            TargetKind::Test => format!("test \"{}\"", self.name()),
    1166            TargetKind::Bench => format!("bench \"{}\"", self.name()),
    1167            TargetKind::ExampleLib(..) | TargetKind::ExampleBin => {
    1168                format!("example \"{}\"", self.name())
    1169            }
    1170            TargetKind::CustomBuild => "build script".to_string(),
    1171        }
    1172    }
    1173}
    1174
    1175impl fmt::Display for Target {
    1176    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    1177        match self.kind() {
    1178            TargetKind::Lib(..) => write!(f, "Target(lib)"),
    1179            TargetKind::Bin => write!(f, "Target(bin: {})", self.name()),
    1180            TargetKind::Test => write!(f, "Target(test: {})", self.name()),
    1181            TargetKind::Bench => write!(f, "Target(bench: {})", self.name()),
    1182            TargetKind::ExampleBin | TargetKind::ExampleLib(..) => {
    1183                write!(f, "Target(example: {})", self.name())
    1184            }
    1185            TargetKind::CustomBuild => write!(f, "Target(script)"),
    1186        }
    1187    }
    1188}
    1189
    1190impl Warnings {
    1191    fn new() -> Warnings {
    1192        Warnings(Vec::new())
    1193    }
    1194
    1195    pub fn add_warning(&mut self, s: String) {
    1196        self.0.push(DelayedWarning {
    1197            message: s,
    1198            is_critical: false,
    1199        })
    1200    }
    1201
    1202    pub fn add_critical_warning(&mut self, s: String) {
    1203        self.0.push(DelayedWarning {
    1204            message: s,
    1205            is_critical: true,
    1206        })
    1207    }
    1208
    1209    pub fn warnings(&self) -> &[DelayedWarning] {
    1210        &self.0
    1211    }
    1212}