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