cargo/core/
manifest.rs

1use std::collections::{BTreeMap, HashMap};
2use std::fmt;
3use std::hash::{Hash, Hasher};
4use std::path::{Path, PathBuf};
5use std::rc::Rc;
6
7use semver::Version;
8use serde::ser;
9use serde::Serialize;
10use url::Url;
11
12use crate::core::interning::InternedString;
13use crate::core::{Dependency, PackageId, PackageIdSpec, SourceId, Summary};
14use crate::core::{Edition, Feature, Features, WorkspaceConfig};
15use crate::util::errors::*;
16use crate::util::toml::{TomlManifest, TomlProfiles};
17use crate::util::{short_hash, Config, Filesystem};
18
19pub enum EitherManifest {
20    Real(Manifest),
21    Virtual(VirtualManifest),
22}
23
24/// Contains all the information about a package, as loaded from a `Cargo.toml`.
25#[derive(Clone, Debug)]
26pub struct Manifest {
27    summary: Summary,
28    targets: Vec<Target>,
29    links: Option<String>,
30    warnings: Warnings,
31    exclude: Vec<String>,
32    include: Vec<String>,
33    metadata: ManifestMetadata,
34    custom_metadata: Option<toml::Value>,
35    profiles: Option<TomlProfiles>,
36    publish: Option<Vec<String>>,
37    publish_lockfile: bool,
38    replace: Vec<(PackageIdSpec, Dependency)>,
39    patch: HashMap<Url, Vec<Dependency>>,
40    workspace: WorkspaceConfig,
41    original: Rc<TomlManifest>,
42    features: Features,
43    edition: Edition,
44    im_a_teapot: Option<bool>,
45    default_run: Option<String>,
46    metabuild: Option<Vec<String>>,
47}
48
49/// When parsing `Cargo.toml`, some warnings should silenced
50/// if the manifest comes from a dependency. `ManifestWarning`
51/// allows this delayed emission of warnings.
52#[derive(Clone, Debug)]
53pub struct DelayedWarning {
54    pub message: String,
55    pub is_critical: bool,
56}
57
58#[derive(Clone, Debug)]
59pub struct Warnings(Vec<DelayedWarning>);
60
61#[derive(Clone, Debug)]
62pub struct VirtualManifest {
63    replace: Vec<(PackageIdSpec, Dependency)>,
64    patch: HashMap<Url, Vec<Dependency>>,
65    workspace: WorkspaceConfig,
66    profiles: Option<TomlProfiles>,
67    warnings: Warnings,
68    features: Features,
69}
70
71/// General metadata about a package which is just blindly uploaded to the
72/// registry.
73///
74/// Note that many of these fields can contain invalid values such as the
75/// homepage, repository, documentation, or license. These fields are not
76/// validated by cargo itself, but rather it is up to the registry when uploaded
77/// to validate these fields. Cargo will itself accept any valid TOML
78/// specification for these values.
79#[derive(PartialEq, Clone, Debug)]
80pub struct ManifestMetadata {
81    pub authors: Vec<String>,
82    pub keywords: Vec<String>,
83    pub categories: Vec<String>,
84    pub license: Option<String>,
85    pub license_file: Option<String>,
86    pub description: Option<String>,   // Not in Markdown
87    pub readme: Option<String>,        // File, not contents
88    pub homepage: Option<String>,      // URL
89    pub repository: Option<String>,    // URL
90    pub documentation: Option<String>, // URL
91    pub badges: BTreeMap<String, BTreeMap<String, String>>,
92    pub links: Option<String>,
93}
94
95#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
96pub enum LibKind {
97    Lib,
98    Rlib,
99    Dylib,
100    ProcMacro,
101    Other(String),
102}
103
104impl LibKind {
105    /// Returns the argument suitable for `--crate-type` to pass to rustc.
106    pub fn crate_type(&self) -> &str {
107        match *self {
108            LibKind::Lib => "lib",
109            LibKind::Rlib => "rlib",
110            LibKind::Dylib => "dylib",
111            LibKind::ProcMacro => "proc-macro",
112            LibKind::Other(ref s) => s,
113        }
114    }
115
116    pub fn linkable(&self) -> bool {
117        match *self {
118            LibKind::Lib | LibKind::Rlib | LibKind::Dylib | LibKind::ProcMacro => true,
119            LibKind::Other(..) => false,
120        }
121    }
122
123    pub fn requires_upstream_objects(&self) -> bool {
124        match *self {
125            // "lib" == "rlib" and is a compilation that doesn't actually
126            // require upstream object files to exist, only upstream metadata
127            // files. As a result, it doesn't require upstream artifacts
128            LibKind::Lib | LibKind::Rlib => false,
129
130            // Everything else, however, is some form of "linkable output" or
131            // something that requires upstream object files.
132            _ => true,
133        }
134    }
135}
136
137impl fmt::Debug for LibKind {
138    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139        self.crate_type().fmt(f)
140    }
141}
142
143impl<'a> From<&'a String> for LibKind {
144    fn from(string: &'a String) -> Self {
145        match string.as_ref() {
146            "lib" => LibKind::Lib,
147            "rlib" => LibKind::Rlib,
148            "dylib" => LibKind::Dylib,
149            "proc-macro" => LibKind::ProcMacro,
150            s => LibKind::Other(s.to_string()),
151        }
152    }
153}
154
155#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
156pub enum TargetKind {
157    Lib(Vec<LibKind>),
158    Bin,
159    Test,
160    Bench,
161    ExampleLib(Vec<LibKind>),
162    ExampleBin,
163    CustomBuild,
164}
165
166impl ser::Serialize for TargetKind {
167    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
168    where
169        S: ser::Serializer,
170    {
171        use self::TargetKind::*;
172        match *self {
173            Lib(ref kinds) => s.collect_seq(kinds.iter().map(LibKind::crate_type)),
174            Bin => ["bin"].serialize(s),
175            ExampleBin | ExampleLib(_) => ["example"].serialize(s),
176            Test => ["test"].serialize(s),
177            CustomBuild => ["custom-build"].serialize(s),
178            Bench => ["bench"].serialize(s),
179        }
180    }
181}
182
183impl fmt::Debug for TargetKind {
184    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185        use self::TargetKind::*;
186        match *self {
187            Lib(ref kinds) => kinds.fmt(f),
188            Bin => "bin".fmt(f),
189            ExampleBin | ExampleLib(_) => "example".fmt(f),
190            Test => "test".fmt(f),
191            CustomBuild => "custom-build".fmt(f),
192            Bench => "bench".fmt(f),
193        }
194    }
195}
196
197impl TargetKind {
198    pub fn description(&self) -> &'static str {
199        match self {
200            TargetKind::Lib(..) => "lib",
201            TargetKind::Bin => "bin",
202            TargetKind::Test => "integration-test",
203            TargetKind::ExampleBin | TargetKind::ExampleLib(..) => "example",
204            TargetKind::Bench => "bench",
205            TargetKind::CustomBuild => "build-script",
206        }
207    }
208
209    /// Returns whether production of this artifact requires the object files
210    /// from dependencies to be available.
211    ///
212    /// This only returns `false` when all we're producing is an rlib, otherwise
213    /// it will return `true`.
214    pub fn requires_upstream_objects(&self) -> bool {
215        match self {
216            TargetKind::Lib(kinds) | TargetKind::ExampleLib(kinds) => {
217                kinds.iter().any(|k| k.requires_upstream_objects())
218            }
219            _ => true,
220        }
221    }
222}
223
224/// Information about a binary, a library, an example, etc. that is part of the
225/// package.
226#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
227pub struct Target {
228    kind: TargetKind,
229    name: String,
230    // Note that the `src_path` here is excluded from the `Hash` implementation
231    // as it's absolute currently and is otherwise a little too brittle for
232    // causing rebuilds. Instead the hash for the path that we send to the
233    // compiler is handled elsewhere.
234    src_path: TargetSourcePath,
235    required_features: Option<Vec<String>>,
236    tested: bool,
237    benched: bool,
238    doc: bool,
239    doctest: bool,
240    harness: bool, // whether to use the test harness (--test)
241    for_host: bool,
242    proc_macro: bool,
243    edition: Edition,
244}
245
246#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
247pub enum TargetSourcePath {
248    Path(PathBuf),
249    Metabuild,
250}
251
252impl TargetSourcePath {
253    pub fn path(&self) -> Option<&Path> {
254        match self {
255            TargetSourcePath::Path(path) => Some(path.as_ref()),
256            TargetSourcePath::Metabuild => None,
257        }
258    }
259
260    pub fn is_path(&self) -> bool {
261        match self {
262            TargetSourcePath::Path(_) => true,
263            _ => false,
264        }
265    }
266}
267
268impl Hash for TargetSourcePath {
269    fn hash<H: Hasher>(&self, _: &mut H) {
270        // ...
271    }
272}
273
274impl fmt::Debug for TargetSourcePath {
275    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
276        match self {
277            TargetSourcePath::Path(path) => path.fmt(f),
278            TargetSourcePath::Metabuild => "metabuild".fmt(f),
279        }
280    }
281}
282
283impl From<PathBuf> for TargetSourcePath {
284    fn from(path: PathBuf) -> Self {
285        assert!(path.is_absolute(), "`{}` is not absolute", path.display());
286        TargetSourcePath::Path(path)
287    }
288}
289
290#[derive(Serialize)]
291struct SerializedTarget<'a> {
292    /// Is this a `--bin bin`, `--lib`, `--example ex`?
293    /// Serialized as a list of strings for historical reasons.
294    kind: &'a TargetKind,
295    /// Corresponds to `--crate-type` compiler attribute.
296    /// See https://doc.rust-lang.org/reference/linkage.html
297    crate_types: Vec<&'a str>,
298    name: &'a str,
299    src_path: Option<&'a PathBuf>,
300    edition: &'a str,
301    #[serde(rename = "required-features", skip_serializing_if = "Option::is_none")]
302    required_features: Option<Vec<&'a str>>,
303    doctest: bool,
304}
305
306impl ser::Serialize for Target {
307    fn serialize<S: ser::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
308        let src_path = match &self.src_path {
309            TargetSourcePath::Path(p) => Some(p),
310            // Unfortunately getting the correct path would require access to
311            // target_dir, which is not available here.
312            TargetSourcePath::Metabuild => None,
313        };
314        SerializedTarget {
315            kind: &self.kind,
316            crate_types: self.rustc_crate_types(),
317            name: &self.name,
318            src_path,
319            edition: &self.edition.to_string(),
320            required_features: self
321                .required_features
322                .as_ref()
323                .map(|rf| rf.iter().map(|s| &**s).collect()),
324            doctest: self.doctest && self.doctestable(),
325        }
326        .serialize(s)
327    }
328}
329
330compact_debug! {
331    impl fmt::Debug for Target {
332        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
333            let (default, default_name) = {
334                match &self.kind {
335                    TargetKind::Lib(kinds) => {
336                        (
337                            Target::lib_target(
338                                &self.name,
339                                kinds.clone(),
340                                self.src_path().path().unwrap().to_path_buf(),
341                                self.edition,
342                            ),
343                            format!("lib_target({:?}, {:?}, {:?}, {:?})",
344                                    self.name, kinds, self.src_path, self.edition),
345                        )
346                    }
347                    TargetKind::CustomBuild => {
348                        match self.src_path {
349                            TargetSourcePath::Path(ref path) => {
350                                (
351                                    Target::custom_build_target(
352                                        &self.name,
353                                        path.to_path_buf(),
354                                        self.edition,
355                                    ),
356                                    format!("custom_build_target({:?}, {:?}, {:?})",
357                                            self.name, path, self.edition),
358                                )
359                            }
360                            TargetSourcePath::Metabuild => {
361                                (
362                                    Target::metabuild_target(&self.name),
363                                    format!("metabuild_target({:?})", self.name),
364                                )
365                            }
366                        }
367                    }
368                    _ => (
369                        Target::new(self.src_path.clone(), self.edition),
370                        format!("with_path({:?}, {:?})", self.src_path, self.edition),
371                    ),
372                }
373            };
374            [debug_the_fields(
375                kind
376                name
377                src_path
378                required_features
379                tested
380                benched
381                doc
382                doctest
383                harness
384                for_host
385                proc_macro
386                edition
387            )]
388        }
389    }
390}
391
392impl Manifest {
393    pub fn new(
394        summary: Summary,
395        targets: Vec<Target>,
396        exclude: Vec<String>,
397        include: Vec<String>,
398        links: Option<String>,
399        metadata: ManifestMetadata,
400        custom_metadata: Option<toml::Value>,
401        profiles: Option<TomlProfiles>,
402        publish: Option<Vec<String>>,
403        publish_lockfile: bool,
404        replace: Vec<(PackageIdSpec, Dependency)>,
405        patch: HashMap<Url, Vec<Dependency>>,
406        workspace: WorkspaceConfig,
407        features: Features,
408        edition: Edition,
409        im_a_teapot: Option<bool>,
410        default_run: Option<String>,
411        original: Rc<TomlManifest>,
412        metabuild: Option<Vec<String>>,
413    ) -> Manifest {
414        Manifest {
415            summary,
416            targets,
417            warnings: Warnings::new(),
418            exclude,
419            include,
420            links,
421            metadata,
422            custom_metadata,
423            profiles,
424            publish,
425            replace,
426            patch,
427            workspace,
428            features,
429            edition,
430            original,
431            im_a_teapot,
432            default_run,
433            publish_lockfile,
434            metabuild,
435        }
436    }
437
438    pub fn dependencies(&self) -> &[Dependency] {
439        self.summary.dependencies()
440    }
441    pub fn exclude(&self) -> &[String] {
442        &self.exclude
443    }
444    pub fn include(&self) -> &[String] {
445        &self.include
446    }
447    pub fn metadata(&self) -> &ManifestMetadata {
448        &self.metadata
449    }
450    pub fn name(&self) -> InternedString {
451        self.package_id().name()
452    }
453    pub fn package_id(&self) -> PackageId {
454        self.summary.package_id()
455    }
456    pub fn summary(&self) -> &Summary {
457        &self.summary
458    }
459    pub fn summary_mut(&mut self) -> &mut Summary {
460        &mut self.summary
461    }
462    pub fn targets(&self) -> &[Target] {
463        &self.targets
464    }
465    pub fn targets_mut(&mut self) -> &mut [Target] {
466        &mut self.targets
467    }
468    pub fn version(&self) -> &Version {
469        self.package_id().version()
470    }
471    pub fn warnings_mut(&mut self) -> &mut Warnings {
472        &mut self.warnings
473    }
474    pub fn warnings(&self) -> &Warnings {
475        &self.warnings
476    }
477    pub fn profiles(&self) -> Option<&TomlProfiles> {
478        self.profiles.as_ref()
479    }
480    pub fn publish(&self) -> &Option<Vec<String>> {
481        &self.publish
482    }
483    pub fn replace(&self) -> &[(PackageIdSpec, Dependency)] {
484        &self.replace
485    }
486    pub fn original(&self) -> &TomlManifest {
487        &self.original
488    }
489    pub fn patch(&self) -> &HashMap<Url, Vec<Dependency>> {
490        &self.patch
491    }
492    pub fn links(&self) -> Option<&str> {
493        self.links.as_deref()
494    }
495
496    pub fn workspace_config(&self) -> &WorkspaceConfig {
497        &self.workspace
498    }
499
500    pub fn features(&self) -> &Features {
501        &self.features
502    }
503
504    pub fn map_source(self, to_replace: SourceId, replace_with: SourceId) -> Manifest {
505        Manifest {
506            summary: self.summary.map_source(to_replace, replace_with),
507            ..self
508        }
509    }
510
511    pub fn feature_gate(&self) -> CargoResult<()> {
512        if self.im_a_teapot.is_some() {
513            self.features
514                .require(Feature::test_dummy_unstable())
515                .chain_err(|| {
516                    anyhow::format_err!(
517                        "the `im-a-teapot` manifest key is unstable and may \
518                         not work properly in England"
519                    )
520                })?;
521        }
522
523        Ok(())
524    }
525
526    // Just a helper function to test out `-Z` flags on Cargo
527    pub fn print_teapot(&self, config: &Config) {
528        if let Some(teapot) = self.im_a_teapot {
529            if config.cli_unstable().print_im_a_teapot {
530                println!("im-a-teapot = {}", teapot);
531            }
532        }
533    }
534
535    pub fn edition(&self) -> Edition {
536        self.edition
537    }
538
539    pub fn custom_metadata(&self) -> Option<&toml::Value> {
540        self.custom_metadata.as_ref()
541    }
542
543    pub fn default_run(&self) -> Option<&str> {
544        self.default_run.as_deref()
545    }
546
547    pub fn metabuild(&self) -> Option<&Vec<String>> {
548        self.metabuild.as_ref()
549    }
550
551    pub fn metabuild_path(&self, target_dir: Filesystem) -> PathBuf {
552        let hash = short_hash(&self.package_id());
553        target_dir
554            .into_path_unlocked()
555            .join(".metabuild")
556            .join(format!("metabuild-{}-{}.rs", self.name(), hash))
557    }
558}
559
560impl VirtualManifest {
561    pub fn new(
562        replace: Vec<(PackageIdSpec, Dependency)>,
563        patch: HashMap<Url, Vec<Dependency>>,
564        workspace: WorkspaceConfig,
565        profiles: Option<TomlProfiles>,
566        features: Features,
567    ) -> VirtualManifest {
568        VirtualManifest {
569            replace,
570            patch,
571            workspace,
572            profiles,
573            warnings: Warnings::new(),
574            features,
575        }
576    }
577
578    pub fn replace(&self) -> &[(PackageIdSpec, Dependency)] {
579        &self.replace
580    }
581
582    pub fn patch(&self) -> &HashMap<Url, Vec<Dependency>> {
583        &self.patch
584    }
585
586    pub fn workspace_config(&self) -> &WorkspaceConfig {
587        &self.workspace
588    }
589
590    pub fn profiles(&self) -> Option<&TomlProfiles> {
591        self.profiles.as_ref()
592    }
593
594    pub fn warnings_mut(&mut self) -> &mut Warnings {
595        &mut self.warnings
596    }
597
598    pub fn warnings(&self) -> &Warnings {
599        &self.warnings
600    }
601
602    pub fn features(&self) -> &Features {
603        &self.features
604    }
605}
606
607impl Target {
608    fn new(src_path: TargetSourcePath, edition: Edition) -> Target {
609        Target {
610            kind: TargetKind::Bin,
611            name: String::new(),
612            src_path,
613            required_features: None,
614            doc: false,
615            doctest: false,
616            harness: true,
617            for_host: false,
618            proc_macro: false,
619            edition,
620            tested: true,
621            benched: true,
622        }
623    }
624
625    fn with_path(src_path: PathBuf, edition: Edition) -> Target {
626        Target::new(TargetSourcePath::from(src_path), edition)
627    }
628
629    pub fn lib_target(
630        name: &str,
631        crate_targets: Vec<LibKind>,
632        src_path: PathBuf,
633        edition: Edition,
634    ) -> Target {
635        Target {
636            kind: TargetKind::Lib(crate_targets),
637            name: name.to_string(),
638            doctest: true,
639            doc: true,
640            ..Target::with_path(src_path, edition)
641        }
642    }
643
644    pub fn bin_target(
645        name: &str,
646        src_path: PathBuf,
647        required_features: Option<Vec<String>>,
648        edition: Edition,
649    ) -> Target {
650        Target {
651            kind: TargetKind::Bin,
652            name: name.to_string(),
653            required_features,
654            doc: true,
655            ..Target::with_path(src_path, edition)
656        }
657    }
658
659    /// Builds a `Target` corresponding to the `build = "build.rs"` entry.
660    pub fn custom_build_target(name: &str, src_path: PathBuf, edition: Edition) -> Target {
661        Target {
662            kind: TargetKind::CustomBuild,
663            name: name.to_string(),
664            for_host: true,
665            benched: false,
666            tested: false,
667            ..Target::with_path(src_path, edition)
668        }
669    }
670
671    pub fn metabuild_target(name: &str) -> Target {
672        Target {
673            kind: TargetKind::CustomBuild,
674            name: name.to_string(),
675            for_host: true,
676            benched: false,
677            tested: false,
678            ..Target::new(TargetSourcePath::Metabuild, Edition::Edition2018)
679        }
680    }
681
682    pub fn example_target(
683        name: &str,
684        crate_targets: Vec<LibKind>,
685        src_path: PathBuf,
686        required_features: Option<Vec<String>>,
687        edition: Edition,
688    ) -> Target {
689        let kind = if crate_targets.is_empty()
690            || crate_targets
691                .iter()
692                .all(|t| *t == LibKind::Other("bin".into()))
693        {
694            TargetKind::ExampleBin
695        } else {
696            TargetKind::ExampleLib(crate_targets)
697        };
698
699        Target {
700            kind,
701            name: name.to_string(),
702            required_features,
703            tested: false,
704            benched: false,
705            ..Target::with_path(src_path, edition)
706        }
707    }
708
709    pub fn test_target(
710        name: &str,
711        src_path: PathBuf,
712        required_features: Option<Vec<String>>,
713        edition: Edition,
714    ) -> Target {
715        Target {
716            kind: TargetKind::Test,
717            name: name.to_string(),
718            required_features,
719            benched: false,
720            ..Target::with_path(src_path, edition)
721        }
722    }
723
724    pub fn bench_target(
725        name: &str,
726        src_path: PathBuf,
727        required_features: Option<Vec<String>>,
728        edition: Edition,
729    ) -> Target {
730        Target {
731            kind: TargetKind::Bench,
732            name: name.to_string(),
733            required_features,
734            tested: false,
735            ..Target::with_path(src_path, edition)
736        }
737    }
738
739    pub fn name(&self) -> &str {
740        &self.name
741    }
742    pub fn crate_name(&self) -> String {
743        self.name.replace("-", "_")
744    }
745    pub fn src_path(&self) -> &TargetSourcePath {
746        &self.src_path
747    }
748    pub fn set_src_path(&mut self, src_path: TargetSourcePath) {
749        self.src_path = src_path;
750    }
751    pub fn required_features(&self) -> Option<&Vec<String>> {
752        self.required_features.as_ref()
753    }
754    pub fn kind(&self) -> &TargetKind {
755        &self.kind
756    }
757    pub fn kind_mut(&mut self) -> &mut TargetKind {
758        &mut self.kind
759    }
760    pub fn tested(&self) -> bool {
761        self.tested
762    }
763    pub fn harness(&self) -> bool {
764        self.harness
765    }
766    pub fn documented(&self) -> bool {
767        self.doc
768    }
769    // A plugin, proc-macro, or build-script.
770    pub fn for_host(&self) -> bool {
771        self.for_host
772    }
773    pub fn proc_macro(&self) -> bool {
774        self.proc_macro
775    }
776    pub fn edition(&self) -> Edition {
777        self.edition
778    }
779    pub fn benched(&self) -> bool {
780        self.benched
781    }
782    pub fn doctested(&self) -> bool {
783        self.doctest
784    }
785
786    pub fn doctestable(&self) -> bool {
787        match self.kind {
788            TargetKind::Lib(ref kinds) => kinds
789                .iter()
790                .any(|k| *k == LibKind::Rlib || *k == LibKind::Lib || *k == LibKind::ProcMacro),
791            _ => false,
792        }
793    }
794
795    pub fn allows_underscores(&self) -> bool {
796        self.is_bin() || self.is_example() || self.is_custom_build()
797    }
798
799    pub fn is_lib(&self) -> bool {
800        match self.kind {
801            TargetKind::Lib(_) => true,
802            _ => false,
803        }
804    }
805
806    pub fn is_dylib(&self) -> bool {
807        match self.kind {
808            TargetKind::Lib(ref libs) => libs.iter().any(|l| *l == LibKind::Dylib),
809            _ => false,
810        }
811    }
812
813    pub fn is_cdylib(&self) -> bool {
814        let libs = match self.kind {
815            TargetKind::Lib(ref libs) => libs,
816            _ => return false,
817        };
818        libs.iter().any(|l| match *l {
819            LibKind::Other(ref s) => s == "cdylib",
820            _ => false,
821        })
822    }
823
824    /// Returns whether this target produces an artifact which can be linked
825    /// into a Rust crate.
826    ///
827    /// This only returns true for certain kinds of libraries.
828    pub fn linkable(&self) -> bool {
829        match self.kind {
830            TargetKind::Lib(ref kinds) => kinds.iter().any(|k| k.linkable()),
831            _ => false,
832        }
833    }
834
835    pub fn is_bin(&self) -> bool {
836        self.kind == TargetKind::Bin
837    }
838
839    pub fn is_example(&self) -> bool {
840        match self.kind {
841            TargetKind::ExampleBin | TargetKind::ExampleLib(..) => true,
842            _ => false,
843        }
844    }
845
846    /// Returns `true` if it is a binary or executable example.
847    /// NOTE: Tests are `false`!
848    pub fn is_executable(&self) -> bool {
849        self.is_bin() || self.is_exe_example()
850    }
851
852    /// Returns `true` if it is an executable example.
853    pub fn is_exe_example(&self) -> bool {
854        // Needed for --all-examples in contexts where only runnable examples make sense
855        match self.kind {
856            TargetKind::ExampleBin => true,
857            _ => false,
858        }
859    }
860
861    pub fn is_test(&self) -> bool {
862        self.kind == TargetKind::Test
863    }
864    pub fn is_bench(&self) -> bool {
865        self.kind == TargetKind::Bench
866    }
867    pub fn is_custom_build(&self) -> bool {
868        self.kind == TargetKind::CustomBuild
869    }
870
871    /// Returns the arguments suitable for `--crate-type` to pass to rustc.
872    pub fn rustc_crate_types(&self) -> Vec<&str> {
873        match self.kind {
874            TargetKind::Lib(ref kinds) | TargetKind::ExampleLib(ref kinds) => {
875                kinds.iter().map(LibKind::crate_type).collect()
876            }
877            TargetKind::CustomBuild
878            | TargetKind::Bench
879            | TargetKind::Test
880            | TargetKind::ExampleBin
881            | TargetKind::Bin => vec!["bin"],
882        }
883    }
884
885    pub fn can_lto(&self) -> bool {
886        match self.kind {
887            TargetKind::Lib(ref v) => {
888                !v.contains(&LibKind::Rlib)
889                    && !v.contains(&LibKind::Dylib)
890                    && !v.contains(&LibKind::Lib)
891            }
892            _ => true,
893        }
894    }
895
896    pub fn set_tested(&mut self, tested: bool) -> &mut Target {
897        self.tested = tested;
898        self
899    }
900    pub fn set_benched(&mut self, benched: bool) -> &mut Target {
901        self.benched = benched;
902        self
903    }
904    pub fn set_doctest(&mut self, doctest: bool) -> &mut Target {
905        self.doctest = doctest;
906        self
907    }
908    pub fn set_for_host(&mut self, for_host: bool) -> &mut Target {
909        self.for_host = for_host;
910        self
911    }
912    pub fn set_proc_macro(&mut self, proc_macro: bool) -> &mut Target {
913        self.proc_macro = proc_macro;
914        self
915    }
916    pub fn set_edition(&mut self, edition: Edition) -> &mut Target {
917        self.edition = edition;
918        self
919    }
920    pub fn set_harness(&mut self, harness: bool) -> &mut Target {
921        self.harness = harness;
922        self
923    }
924    pub fn set_doc(&mut self, doc: bool) -> &mut Target {
925        self.doc = doc;
926        self
927    }
928
929    pub fn description_named(&self) -> String {
930        match self.kind {
931            TargetKind::Lib(..) => "lib".to_string(),
932            TargetKind::Bin => format!("bin \"{}\"", self.name()),
933            TargetKind::Test => format!("test \"{}\"", self.name()),
934            TargetKind::Bench => format!("bench \"{}\"", self.name()),
935            TargetKind::ExampleLib(..) | TargetKind::ExampleBin => {
936                format!("example \"{}\"", self.name())
937            }
938            TargetKind::CustomBuild => "custom-build".to_string(),
939        }
940    }
941}
942
943impl fmt::Display for Target {
944    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
945        match self.kind {
946            TargetKind::Lib(..) => write!(f, "Target(lib)"),
947            TargetKind::Bin => write!(f, "Target(bin: {})", self.name),
948            TargetKind::Test => write!(f, "Target(test: {})", self.name),
949            TargetKind::Bench => write!(f, "Target(bench: {})", self.name),
950            TargetKind::ExampleBin | TargetKind::ExampleLib(..) => {
951                write!(f, "Target(example: {})", self.name)
952            }
953            TargetKind::CustomBuild => write!(f, "Target(script)"),
954        }
955    }
956}
957
958impl Warnings {
959    fn new() -> Warnings {
960        Warnings(Vec::new())
961    }
962
963    pub fn add_warning(&mut self, s: String) {
964        self.0.push(DelayedWarning {
965            message: s,
966            is_critical: false,
967        })
968    }
969
970    pub fn add_critical_warning(&mut self, s: String) {
971        self.0.push(DelayedWarning {
972            message: s,
973            is_critical: true,
974        })
975    }
976
977    pub fn warnings(&self) -> &[DelayedWarning] {
978        &self.0
979    }
980}