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 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#[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 name_inferred: bool,
308 bin_name: Option<String>,
310 src_path: TargetSourcePath,
315 required_features: Option<Vec<String>>,
316 tested: bool,
317 benched: bool,
318 doc: bool,
319 doctest: bool,
320 harness: bool, 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 }
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 kind: &'a TargetKind,
373 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 doc: bool,
384 doctest: bool,
385 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 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 pub fn contents(&self) -> &str {
549 self.contents.as_str()
550 }
551 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 pub fn document(&self) -> &toml_edit::ImDocument<String> {
558 &self.document
559 }
560 pub fn original_toml(&self) -> &TomlManifest {
562 &self.original_toml
563 }
564 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 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 pub fn unstable_features(&self) -> &Features {
645 &self.unstable_features
646 }
647
648 pub fn resolve_behavior(&self) -> Option<ResolveBehavior> {
652 self.resolve_behavior
653 }
654
655 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 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 pub fn contents(&self) -> &str {
755 self.contents.as_str()
756 }
757 pub fn document(&self) -> &toml_edit::ImDocument<String> {
759 &self.document
760 }
761 pub fn original_toml(&self) -> &TomlManifest {
763 &self.original_toml
764 }
765 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 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 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 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 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 pub fn is_executable(&self) -> bool {
1052 self.is_bin() || self.is_exe_example()
1053 }
1054
1055 pub fn is_exe_example(&self) -> bool {
1057 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 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}