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#[derive(Clone, Debug)]
63pub struct Manifest {
64 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 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#[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 contents: Rc<String>,
112 document: Rc<toml_edit::ImDocument<String>>,
113 original_toml: Rc<TomlManifest>,
114 normalized_toml: Rc<TomlManifest>,
115
116 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#[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>, pub readme: Option<String>, pub homepage: Option<String>, pub repository: Option<String>, pub documentation: Option<String>, pub badges: BTreeMap<String, BTreeMap<String, String>>,
146 pub links: Option<String>,
147 pub rust_version: Option<RustVersion>,
148}
149
150impl ManifestMetadata {
151 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
200metadata_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 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 pub fn benefits_from_no_embed_metadata(&self) -> bool {
285 match self {
286 TargetKind::Lib(kinds) | TargetKind::ExampleLib(kinds) => {
287 kinds.iter().any(|k| k.benefits_from_no_embed_metadata())
288 }
289 _ => false,
290 }
291 }
292
293 pub fn rustc_crate_types(&self) -> Vec<CrateType> {
295 match self {
296 TargetKind::Lib(kinds) | TargetKind::ExampleLib(kinds) => kinds.clone(),
297 TargetKind::CustomBuild
298 | TargetKind::Bench
299 | TargetKind::Test
300 | TargetKind::ExampleBin
301 | TargetKind::Bin => vec![CrateType::Bin],
302 }
303 }
304}
305
306#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
309pub struct Target {
310 inner: Arc<TargetInner>,
311}
312
313#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
314struct TargetInner {
315 kind: TargetKind,
316 name: String,
317 name_inferred: bool,
319 bin_name: Option<String>,
321 src_path: TargetSourcePath,
326 required_features: Option<Vec<String>>,
327 tested: bool,
328 benched: bool,
329 doc: bool,
330 doctest: bool,
331 harness: bool, for_host: bool,
333 proc_macro: bool,
334 edition: Edition,
335 doc_scrape_examples: RustdocScrapeExamples,
336}
337
338#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
339pub enum TargetSourcePath {
340 Path(PathBuf),
341 Metabuild,
342}
343
344impl TargetSourcePath {
345 pub fn path(&self) -> Option<&Path> {
346 match self {
347 TargetSourcePath::Path(path) => Some(path.as_ref()),
348 TargetSourcePath::Metabuild => None,
349 }
350 }
351
352 pub fn is_path(&self) -> bool {
353 matches!(self, TargetSourcePath::Path(_))
354 }
355}
356
357impl Hash for TargetSourcePath {
358 fn hash<H: Hasher>(&self, _: &mut H) {
359 }
361}
362
363impl fmt::Debug for TargetSourcePath {
364 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
365 match self {
366 TargetSourcePath::Path(path) => path.fmt(f),
367 TargetSourcePath::Metabuild => "metabuild".fmt(f),
368 }
369 }
370}
371
372impl From<PathBuf> for TargetSourcePath {
373 fn from(path: PathBuf) -> Self {
374 assert!(path.is_absolute(), "`{}` is not absolute", path.display());
375 TargetSourcePath::Path(path)
376 }
377}
378
379#[derive(Serialize)]
380struct SerializedTarget<'a> {
381 kind: &'a TargetKind,
384 crate_types: Vec<CrateType>,
387 name: &'a str,
388 src_path: Option<&'a PathBuf>,
389 edition: &'a str,
390 #[serde(rename = "required-features", skip_serializing_if = "Option::is_none")]
391 required_features: Option<Vec<&'a str>>,
392 doc: bool,
395 doctest: bool,
396 test: bool,
398}
399
400impl ser::Serialize for Target {
401 fn serialize<S: ser::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
402 let src_path = match self.src_path() {
403 TargetSourcePath::Path(p) => Some(p),
404 TargetSourcePath::Metabuild => None,
407 };
408 SerializedTarget {
409 kind: self.kind(),
410 crate_types: self.rustc_crate_types(),
411 name: self.name(),
412 src_path,
413 edition: &self.edition().to_string(),
414 required_features: self
415 .required_features()
416 .map(|rf| rf.iter().map(|s| s.as_str()).collect()),
417 doc: self.documented(),
418 doctest: self.doctested() && self.doctestable(),
419 test: self.tested(),
420 }
421 .serialize(s)
422 }
423}
424
425impl fmt::Debug for Target {
426 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
427 self.inner.fmt(f)
428 }
429}
430
431compact_debug! {
432 impl fmt::Debug for TargetInner {
433 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
434 let (default, default_name) = {
435 match &self.kind {
436 TargetKind::Lib(kinds) => {
437 (
438 Target::lib_target(
439 &self.name,
440 kinds.clone(),
441 self.src_path.path().unwrap().to_path_buf(),
442 self.edition,
443 ).inner,
444 format!("lib_target({:?}, {:?}, {:?}, {:?})",
445 self.name, kinds, self.src_path, self.edition),
446 )
447 }
448 TargetKind::CustomBuild => {
449 match self.src_path {
450 TargetSourcePath::Path(ref path) => {
451 (
452 Target::custom_build_target(
453 &self.name,
454 path.to_path_buf(),
455 self.edition,
456 ).inner,
457 format!("custom_build_target({:?}, {:?}, {:?})",
458 self.name, path, self.edition),
459 )
460 }
461 TargetSourcePath::Metabuild => {
462 (
463 Target::metabuild_target(&self.name).inner,
464 format!("metabuild_target({:?})", self.name),
465 )
466 }
467 }
468 }
469 _ => (
470 Target::new(self.src_path.clone(), self.edition).inner,
471 format!("with_path({:?}, {:?})", self.src_path, self.edition),
472 ),
473 }
474 };
475 [debug_the_fields(
476 kind
477 name
478 name_inferred
479 bin_name
480 src_path
481 required_features
482 tested
483 benched
484 doc
485 doctest
486 harness
487 for_host
488 proc_macro
489 edition
490 doc_scrape_examples
491 )]
492 }
493 }
494}
495
496impl Manifest {
497 pub fn new(
498 contents: Rc<String>,
499 document: Rc<toml_edit::ImDocument<String>>,
500 original_toml: Rc<TomlManifest>,
501 normalized_toml: Rc<TomlManifest>,
502 summary: Summary,
503
504 default_kind: Option<CompileKind>,
505 forced_kind: Option<CompileKind>,
506 targets: Vec<Target>,
507 exclude: Vec<String>,
508 include: Vec<String>,
509 links: Option<String>,
510 metadata: ManifestMetadata,
511 custom_metadata: Option<toml::Value>,
512 publish: Option<Vec<String>>,
513 replace: Vec<(PackageIdSpec, Dependency)>,
514 patch: HashMap<Url, Vec<Dependency>>,
515 workspace: WorkspaceConfig,
516 unstable_features: Features,
517 edition: Edition,
518 rust_version: Option<RustVersion>,
519 im_a_teapot: Option<bool>,
520 default_run: Option<String>,
521 metabuild: Option<Vec<String>>,
522 resolve_behavior: Option<ResolveBehavior>,
523 lint_rustflags: Vec<String>,
524 embedded: bool,
525 ) -> Manifest {
526 Manifest {
527 contents,
528 document,
529 original_toml,
530 normalized_toml,
531 summary,
532
533 default_kind,
534 forced_kind,
535 targets,
536 warnings: Warnings::new(),
537 exclude,
538 include,
539 links,
540 metadata,
541 custom_metadata,
542 publish,
543 replace,
544 patch,
545 workspace,
546 unstable_features,
547 edition,
548 rust_version,
549 im_a_teapot,
550 default_run,
551 metabuild,
552 resolve_behavior,
553 lint_rustflags,
554 embedded,
555 }
556 }
557
558 pub fn contents(&self) -> &str {
560 self.contents.as_str()
561 }
562 pub fn to_normalized_contents(&self) -> CargoResult<String> {
564 let toml = toml::to_string_pretty(self.normalized_toml())?;
565 Ok(format!("{}\n{}", MANIFEST_PREAMBLE, toml))
566 }
567 pub fn document(&self) -> &toml_edit::ImDocument<String> {
569 &self.document
570 }
571 pub fn original_toml(&self) -> &TomlManifest {
573 &self.original_toml
574 }
575 pub fn normalized_toml(&self) -> &TomlManifest {
582 &self.normalized_toml
583 }
584 pub fn summary(&self) -> &Summary {
585 &self.summary
586 }
587 pub fn summary_mut(&mut self) -> &mut Summary {
588 &mut self.summary
589 }
590
591 pub fn dependencies(&self) -> &[Dependency] {
592 self.summary.dependencies()
593 }
594 pub fn default_kind(&self) -> Option<CompileKind> {
595 self.default_kind
596 }
597 pub fn forced_kind(&self) -> Option<CompileKind> {
598 self.forced_kind
599 }
600 pub fn exclude(&self) -> &[String] {
601 &self.exclude
602 }
603 pub fn include(&self) -> &[String] {
604 &self.include
605 }
606 pub fn metadata(&self) -> &ManifestMetadata {
607 &self.metadata
608 }
609 pub fn name(&self) -> InternedString {
610 self.package_id().name()
611 }
612 pub fn package_id(&self) -> PackageId {
613 self.summary.package_id()
614 }
615 pub fn targets(&self) -> &[Target] {
616 &self.targets
617 }
618 pub fn targets_mut(&mut self) -> &mut [Target] {
620 &mut self.targets
621 }
622 pub fn version(&self) -> &Version {
623 self.package_id().version()
624 }
625 pub fn warnings_mut(&mut self) -> &mut Warnings {
626 &mut self.warnings
627 }
628 pub fn warnings(&self) -> &Warnings {
629 &self.warnings
630 }
631 pub fn profiles(&self) -> Option<&TomlProfiles> {
632 self.normalized_toml.profile.as_ref()
633 }
634 pub fn publish(&self) -> &Option<Vec<String>> {
635 &self.publish
636 }
637 pub fn replace(&self) -> &[(PackageIdSpec, Dependency)] {
638 &self.replace
639 }
640 pub fn patch(&self) -> &HashMap<Url, Vec<Dependency>> {
641 &self.patch
642 }
643 pub fn links(&self) -> Option<&str> {
644 self.links.as_deref()
645 }
646 pub fn is_embedded(&self) -> bool {
647 self.embedded
648 }
649
650 pub fn workspace_config(&self) -> &WorkspaceConfig {
651 &self.workspace
652 }
653
654 pub fn unstable_features(&self) -> &Features {
656 &self.unstable_features
657 }
658
659 pub fn resolve_behavior(&self) -> Option<ResolveBehavior> {
663 self.resolve_behavior
664 }
665
666 pub fn lint_rustflags(&self) -> &[String] {
668 self.lint_rustflags.as_slice()
669 }
670
671 pub fn map_source(self, to_replace: SourceId, replace_with: SourceId) -> Manifest {
672 Manifest {
673 summary: self.summary.map_source(to_replace, replace_with),
674 ..self
675 }
676 }
677
678 pub fn feature_gate(&self) -> CargoResult<()> {
679 if self.im_a_teapot.is_some() {
680 self.unstable_features
681 .require(Feature::test_dummy_unstable())
682 .with_context(|| {
683 "the `im-a-teapot` manifest key is unstable and may \
684 not work properly in England"
685 })?;
686 }
687
688 if self.default_kind.is_some() || self.forced_kind.is_some() {
689 self.unstable_features
690 .require(Feature::per_package_target())
691 .with_context(|| {
692 "the `package.default-target` and `package.forced-target` \
693 manifest keys are unstable and may not work properly"
694 })?;
695 }
696
697 Ok(())
698 }
699
700 pub fn print_teapot(&self, gctx: &GlobalContext) {
702 if let Some(teapot) = self.im_a_teapot {
703 if gctx.cli_unstable().print_im_a_teapot {
704 crate::drop_println!(gctx, "im-a-teapot = {}", teapot);
705 }
706 }
707 }
708
709 pub fn edition(&self) -> Edition {
710 self.edition
711 }
712
713 pub fn rust_version(&self) -> Option<&RustVersion> {
714 self.rust_version.as_ref()
715 }
716
717 pub fn custom_metadata(&self) -> Option<&toml::Value> {
718 self.custom_metadata.as_ref()
719 }
720
721 pub fn default_run(&self) -> Option<&str> {
722 self.default_run.as_deref()
723 }
724
725 pub fn metabuild(&self) -> Option<&Vec<String>> {
726 self.metabuild.as_ref()
727 }
728
729 pub fn metabuild_path(&self, target_dir: Filesystem) -> PathBuf {
730 let hash = short_hash(&self.package_id());
731 target_dir
732 .into_path_unlocked()
733 .join(".metabuild")
734 .join(format!("metabuild-{}-{}.rs", self.name(), hash))
735 }
736}
737
738impl VirtualManifest {
739 pub fn new(
740 contents: Rc<String>,
741 document: Rc<toml_edit::ImDocument<String>>,
742 original_toml: Rc<TomlManifest>,
743 normalized_toml: Rc<TomlManifest>,
744 replace: Vec<(PackageIdSpec, Dependency)>,
745 patch: HashMap<Url, Vec<Dependency>>,
746 workspace: WorkspaceConfig,
747 features: Features,
748 resolve_behavior: Option<ResolveBehavior>,
749 ) -> VirtualManifest {
750 VirtualManifest {
751 contents,
752 document,
753 original_toml,
754 normalized_toml,
755 replace,
756 patch,
757 workspace,
758 warnings: Warnings::new(),
759 features,
760 resolve_behavior,
761 }
762 }
763
764 pub fn contents(&self) -> &str {
766 self.contents.as_str()
767 }
768 pub fn document(&self) -> &toml_edit::ImDocument<String> {
770 &self.document
771 }
772 pub fn original_toml(&self) -> &TomlManifest {
774 &self.original_toml
775 }
776 pub fn normalized_toml(&self) -> &TomlManifest {
778 &self.normalized_toml
779 }
780
781 pub fn replace(&self) -> &[(PackageIdSpec, Dependency)] {
782 &self.replace
783 }
784
785 pub fn patch(&self) -> &HashMap<Url, Vec<Dependency>> {
786 &self.patch
787 }
788
789 pub fn workspace_config(&self) -> &WorkspaceConfig {
790 &self.workspace
791 }
792
793 pub fn profiles(&self) -> Option<&TomlProfiles> {
794 self.normalized_toml.profile.as_ref()
795 }
796
797 pub fn warnings_mut(&mut self) -> &mut Warnings {
798 &mut self.warnings
799 }
800
801 pub fn warnings(&self) -> &Warnings {
802 &self.warnings
803 }
804
805 pub fn unstable_features(&self) -> &Features {
806 &self.features
807 }
808
809 pub fn resolve_behavior(&self) -> Option<ResolveBehavior> {
813 self.resolve_behavior
814 }
815}
816
817impl Target {
818 fn new(src_path: TargetSourcePath, edition: Edition) -> Target {
819 Target {
820 inner: Arc::new(TargetInner {
821 kind: TargetKind::Bin,
822 name: String::new(),
823 name_inferred: false,
824 bin_name: None,
825 src_path,
826 required_features: None,
827 doc: false,
828 doctest: false,
829 harness: true,
830 for_host: false,
831 proc_macro: false,
832 doc_scrape_examples: RustdocScrapeExamples::Unset,
833 edition,
834 tested: true,
835 benched: true,
836 }),
837 }
838 }
839
840 fn with_path(src_path: PathBuf, edition: Edition) -> Target {
841 Target::new(TargetSourcePath::from(src_path), edition)
842 }
843
844 pub fn lib_target(
845 name: &str,
846 crate_targets: Vec<CrateType>,
847 src_path: PathBuf,
848 edition: Edition,
849 ) -> Target {
850 let mut target = Target::with_path(src_path, edition);
851 target
852 .set_kind(TargetKind::Lib(crate_targets))
853 .set_name(name)
854 .set_doctest(true)
855 .set_doc(true);
856 target
857 }
858
859 pub fn bin_target(
860 name: &str,
861 bin_name: Option<String>,
862 src_path: PathBuf,
863 required_features: Option<Vec<String>>,
864 edition: Edition,
865 ) -> Target {
866 let mut target = Target::with_path(src_path, edition);
867 target
868 .set_kind(TargetKind::Bin)
869 .set_name(name)
870 .set_binary_name(bin_name)
871 .set_required_features(required_features)
872 .set_doc(true);
873 target
874 }
875
876 pub fn custom_build_target(name: &str, src_path: PathBuf, edition: Edition) -> Target {
878 let mut target = Target::with_path(src_path, edition);
879 target
880 .set_kind(TargetKind::CustomBuild)
881 .set_name(name)
882 .set_for_host(true)
883 .set_benched(false)
884 .set_tested(false)
885 .set_doc_scrape_examples(RustdocScrapeExamples::Disabled);
886 target
887 }
888
889 pub fn metabuild_target(name: &str) -> Target {
890 let mut target = Target::new(TargetSourcePath::Metabuild, Edition::Edition2018);
891 target
892 .set_kind(TargetKind::CustomBuild)
893 .set_name(name)
894 .set_for_host(true)
895 .set_benched(false)
896 .set_tested(false)
897 .set_doc_scrape_examples(RustdocScrapeExamples::Disabled);
898 target
899 }
900
901 pub fn example_target(
902 name: &str,
903 crate_targets: Vec<CrateType>,
904 src_path: PathBuf,
905 required_features: Option<Vec<String>>,
906 edition: Edition,
907 ) -> Target {
908 let kind = if crate_targets.is_empty() || crate_targets.iter().all(|t| *t == CrateType::Bin)
909 {
910 TargetKind::ExampleBin
911 } else {
912 TargetKind::ExampleLib(crate_targets)
913 };
914 let mut target = Target::with_path(src_path, edition);
915 target
916 .set_kind(kind)
917 .set_name(name)
918 .set_required_features(required_features)
919 .set_tested(false)
920 .set_benched(false);
921 target
922 }
923
924 pub fn test_target(
925 name: &str,
926 src_path: PathBuf,
927 required_features: Option<Vec<String>>,
928 edition: Edition,
929 ) -> Target {
930 let mut target = Target::with_path(src_path, edition);
931 target
932 .set_kind(TargetKind::Test)
933 .set_name(name)
934 .set_required_features(required_features)
935 .set_benched(false);
936 target
937 }
938
939 pub fn bench_target(
940 name: &str,
941 src_path: PathBuf,
942 required_features: Option<Vec<String>>,
943 edition: Edition,
944 ) -> Target {
945 let mut target = Target::with_path(src_path, edition);
946 target
947 .set_kind(TargetKind::Bench)
948 .set_name(name)
949 .set_required_features(required_features)
950 .set_tested(false);
951 target
952 }
953
954 pub fn name(&self) -> &str {
955 &self.inner.name
956 }
957 pub fn name_inferred(&self) -> bool {
958 self.inner.name_inferred
959 }
960 pub fn crate_name(&self) -> String {
961 self.name().replace("-", "_")
962 }
963 pub fn src_path(&self) -> &TargetSourcePath {
964 &self.inner.src_path
965 }
966 pub fn set_src_path(&mut self, src_path: TargetSourcePath) {
967 Arc::make_mut(&mut self.inner).src_path = src_path;
968 }
969 pub fn required_features(&self) -> Option<&Vec<String>> {
970 self.inner.required_features.as_ref()
971 }
972 pub fn kind(&self) -> &TargetKind {
973 &self.inner.kind
974 }
975 pub fn tested(&self) -> bool {
976 self.inner.tested
977 }
978 pub fn harness(&self) -> bool {
979 self.inner.harness
980 }
981 pub fn documented(&self) -> bool {
982 self.inner.doc
983 }
984 pub fn for_host(&self) -> bool {
986 self.inner.for_host
987 }
988 pub fn proc_macro(&self) -> bool {
989 self.inner.proc_macro
990 }
991 pub fn edition(&self) -> Edition {
992 self.inner.edition
993 }
994 pub fn doc_scrape_examples(&self) -> RustdocScrapeExamples {
995 self.inner.doc_scrape_examples
996 }
997 pub fn benched(&self) -> bool {
998 self.inner.benched
999 }
1000 pub fn doctested(&self) -> bool {
1001 self.inner.doctest
1002 }
1003
1004 pub fn doctestable(&self) -> bool {
1005 match self.kind() {
1006 TargetKind::Lib(ref kinds) => kinds.iter().any(|k| {
1007 *k == CrateType::Rlib || *k == CrateType::Lib || *k == CrateType::ProcMacro
1008 }),
1009 _ => false,
1010 }
1011 }
1012
1013 pub fn is_lib(&self) -> bool {
1014 matches!(self.kind(), TargetKind::Lib(_))
1015 }
1016
1017 pub fn is_dylib(&self) -> bool {
1018 match self.kind() {
1019 TargetKind::Lib(libs) => libs.iter().any(|l| *l == CrateType::Dylib),
1020 _ => false,
1021 }
1022 }
1023
1024 pub fn is_cdylib(&self) -> bool {
1025 match self.kind() {
1026 TargetKind::Lib(libs) => libs.iter().any(|l| *l == CrateType::Cdylib),
1027 _ => false,
1028 }
1029 }
1030
1031 pub fn is_staticlib(&self) -> bool {
1032 match self.kind() {
1033 TargetKind::Lib(libs) => libs.iter().any(|l| *l == CrateType::Staticlib),
1034 _ => false,
1035 }
1036 }
1037
1038 pub fn is_linkable(&self) -> bool {
1043 match self.kind() {
1044 TargetKind::Lib(kinds) => kinds.iter().any(|k| k.is_linkable()),
1045 _ => false,
1046 }
1047 }
1048
1049 pub fn is_bin(&self) -> bool {
1050 *self.kind() == TargetKind::Bin
1051 }
1052
1053 pub fn is_example(&self) -> bool {
1054 matches!(
1055 self.kind(),
1056 TargetKind::ExampleBin | TargetKind::ExampleLib(..)
1057 )
1058 }
1059
1060 pub fn is_executable(&self) -> bool {
1063 self.is_bin() || self.is_exe_example()
1064 }
1065
1066 pub fn is_exe_example(&self) -> bool {
1068 matches!(self.kind(), TargetKind::ExampleBin)
1070 }
1071
1072 pub fn is_test(&self) -> bool {
1073 *self.kind() == TargetKind::Test
1074 }
1075 pub fn is_bench(&self) -> bool {
1076 *self.kind() == TargetKind::Bench
1077 }
1078 pub fn is_custom_build(&self) -> bool {
1079 *self.kind() == TargetKind::CustomBuild
1080 }
1081
1082 pub fn rustc_crate_types(&self) -> Vec<CrateType> {
1084 self.kind().rustc_crate_types()
1085 }
1086
1087 pub fn set_tested(&mut self, tested: bool) -> &mut Target {
1088 Arc::make_mut(&mut self.inner).tested = tested;
1089 self
1090 }
1091 pub fn set_benched(&mut self, benched: bool) -> &mut Target {
1092 Arc::make_mut(&mut self.inner).benched = benched;
1093 self
1094 }
1095 pub fn set_doctest(&mut self, doctest: bool) -> &mut Target {
1096 Arc::make_mut(&mut self.inner).doctest = doctest;
1097 self
1098 }
1099 pub fn set_for_host(&mut self, for_host: bool) -> &mut Target {
1100 Arc::make_mut(&mut self.inner).for_host = for_host;
1101 self
1102 }
1103 pub fn set_proc_macro(&mut self, proc_macro: bool) -> &mut Target {
1104 Arc::make_mut(&mut self.inner).proc_macro = proc_macro;
1105 self
1106 }
1107 pub fn set_edition(&mut self, edition: Edition) -> &mut Target {
1108 Arc::make_mut(&mut self.inner).edition = edition;
1109 self
1110 }
1111 pub fn set_doc_scrape_examples(
1112 &mut self,
1113 doc_scrape_examples: RustdocScrapeExamples,
1114 ) -> &mut Target {
1115 Arc::make_mut(&mut self.inner).doc_scrape_examples = doc_scrape_examples;
1116 self
1117 }
1118 pub fn set_harness(&mut self, harness: bool) -> &mut Target {
1119 Arc::make_mut(&mut self.inner).harness = harness;
1120 self
1121 }
1122 pub fn set_doc(&mut self, doc: bool) -> &mut Target {
1123 Arc::make_mut(&mut self.inner).doc = doc;
1124 self
1125 }
1126 pub fn set_kind(&mut self, kind: TargetKind) -> &mut Target {
1127 Arc::make_mut(&mut self.inner).kind = kind;
1128 self
1129 }
1130 pub fn set_name(&mut self, name: &str) -> &mut Target {
1131 Arc::make_mut(&mut self.inner).name = name.to_string();
1132 self
1133 }
1134 pub fn set_name_inferred(&mut self, inferred: bool) -> &mut Target {
1135 Arc::make_mut(&mut self.inner).name_inferred = inferred;
1136 self
1137 }
1138 pub fn set_binary_name(&mut self, bin_name: Option<String>) -> &mut Target {
1139 Arc::make_mut(&mut self.inner).bin_name = bin_name;
1140 self
1141 }
1142 pub fn set_required_features(&mut self, required_features: Option<Vec<String>>) -> &mut Target {
1143 Arc::make_mut(&mut self.inner).required_features = required_features;
1144 self
1145 }
1146 pub fn binary_filename(&self) -> Option<String> {
1147 self.inner.bin_name.clone()
1148 }
1149 pub fn description_named(&self) -> String {
1150 match self.kind() {
1151 TargetKind::Lib(..) => "lib".to_string(),
1152 TargetKind::Bin => format!("bin \"{}\"", self.name()),
1153 TargetKind::Test => format!("test \"{}\"", self.name()),
1154 TargetKind::Bench => format!("bench \"{}\"", self.name()),
1155 TargetKind::ExampleLib(..) | TargetKind::ExampleBin => {
1156 format!("example \"{}\"", self.name())
1157 }
1158 TargetKind::CustomBuild => "build script".to_string(),
1159 }
1160 }
1161}
1162
1163impl fmt::Display for Target {
1164 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1165 match self.kind() {
1166 TargetKind::Lib(..) => write!(f, "Target(lib)"),
1167 TargetKind::Bin => write!(f, "Target(bin: {})", self.name()),
1168 TargetKind::Test => write!(f, "Target(test: {})", self.name()),
1169 TargetKind::Bench => write!(f, "Target(bench: {})", self.name()),
1170 TargetKind::ExampleBin | TargetKind::ExampleLib(..) => {
1171 write!(f, "Target(example: {})", self.name())
1172 }
1173 TargetKind::CustomBuild => write!(f, "Target(script)"),
1174 }
1175 }
1176}
1177
1178impl Warnings {
1179 fn new() -> Warnings {
1180 Warnings(Vec::new())
1181 }
1182
1183 pub fn add_warning(&mut self, s: String) {
1184 self.0.push(DelayedWarning {
1185 message: s,
1186 is_critical: false,
1187 })
1188 }
1189
1190 pub fn add_critical_warning(&mut self, s: String) {
1191 self.0.push(DelayedWarning {
1192 message: s,
1193 is_critical: true,
1194 })
1195 }
1196
1197 pub fn warnings(&self) -> &[DelayedWarning] {
1198 &self.0
1199 }
1200}