1 use std
::collections
::{BTreeMap, HashMap}
;
3 use std
::hash
::{Hash, Hasher}
;
4 use std
::path
::{Path, PathBuf}
;
12 use crate::core
::interning
::InternedString
;
13 use crate::core
::profiles
::Profiles
;
14 use crate::core
::{Dependency, PackageId, PackageIdSpec, SourceId, Summary}
;
15 use crate::core
::{Edition, Feature, Features, WorkspaceConfig}
;
16 use crate::util
::errors
::*;
17 use crate::util
::toml
::TomlManifest
;
18 use crate::util
::{short_hash, Config, Filesystem}
;
20 pub enum EitherManifest
{
22 Virtual(VirtualManifest
),
25 /// Contains all the information about a package, as loaded from a `Cargo.toml`.
26 #[derive(Clone, Debug)]
30 links
: Option
<String
>,
34 metadata
: ManifestMetadata
,
35 custom_metadata
: Option
<toml
::Value
>,
37 publish
: Option
<Vec
<String
>>,
38 publish_lockfile
: bool
,
39 replace
: Vec
<(PackageIdSpec
, Dependency
)>,
40 patch
: HashMap
<Url
, Vec
<Dependency
>>,
41 workspace
: WorkspaceConfig
,
42 original
: Rc
<TomlManifest
>,
45 im_a_teapot
: Option
<bool
>,
46 default_run
: Option
<String
>,
47 metabuild
: Option
<Vec
<String
>>,
50 /// When parsing `Cargo.toml`, some warnings should silenced
51 /// if the manifest comes from a dependency. `ManifestWarning`
52 /// allows this delayed emission of warnings.
53 #[derive(Clone, Debug)]
54 pub struct DelayedWarning
{
56 pub is_critical
: bool
,
59 #[derive(Clone, Debug)]
60 pub struct Warnings(Vec
<DelayedWarning
>);
62 #[derive(Clone, Debug)]
63 pub struct VirtualManifest
{
64 replace
: Vec
<(PackageIdSpec
, Dependency
)>,
65 patch
: HashMap
<Url
, Vec
<Dependency
>>,
66 workspace
: WorkspaceConfig
,
72 /// General metadata about a package which is just blindly uploaded to the
75 /// Note that many of these fields can contain invalid values such as the
76 /// homepage, repository, documentation, or license. These fields are not
77 /// validated by cargo itself, but rather it is up to the registry when uploaded
78 /// to validate these fields. Cargo will itself accept any valid TOML
79 /// specification for these values.
80 #[derive(PartialEq, Clone, Debug)]
81 pub struct ManifestMetadata
{
82 pub authors
: Vec
<String
>,
83 pub keywords
: Vec
<String
>,
84 pub categories
: Vec
<String
>,
85 pub license
: Option
<String
>,
86 pub license_file
: Option
<String
>,
87 pub description
: Option
<String
>, // Not in Markdown
88 pub readme
: Option
<String
>, // File, not contents
89 pub homepage
: Option
<String
>, // URL
90 pub repository
: Option
<String
>, // URL
91 pub documentation
: Option
<String
>, // URL
92 pub badges
: BTreeMap
<String
, BTreeMap
<String
, String
>>,
93 pub links
: Option
<String
>,
96 #[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
106 /// Returns the argument suitable for `--crate-type` to pass to rustc.
107 pub fn crate_type(&self) -> &str {
109 LibKind
::Lib
=> "lib",
110 LibKind
::Rlib
=> "rlib",
111 LibKind
::Dylib
=> "dylib",
112 LibKind
::ProcMacro
=> "proc-macro",
113 LibKind
::Other(ref s
) => s
,
117 pub fn linkable(&self) -> bool
{
119 LibKind
::Lib
| LibKind
::Rlib
| LibKind
::Dylib
| LibKind
::ProcMacro
=> true,
120 LibKind
::Other(..) => false,
124 pub fn requires_upstream_objects(&self) -> bool
{
126 // "lib" == "rlib" and is a compilation that doesn't actually
127 // require upstream object files to exist, only upstream metadata
128 // files. As a result, it doesn't require upstream artifacts
129 LibKind
::Lib
| LibKind
::Rlib
=> false,
131 // Everything else, however, is some form of "linkable output" or
132 // something that requires upstream object files.
138 impl fmt
::Debug
for LibKind
{
139 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
140 self.crate_type().fmt(f
)
144 impl<'a
> From
<&'a String
> for LibKind
{
145 fn from(string
: &'a String
) -> Self {
146 match string
.as_ref() {
147 "lib" => LibKind
::Lib
,
148 "rlib" => LibKind
::Rlib
,
149 "dylib" => LibKind
::Dylib
,
150 "proc-macro" => LibKind
::ProcMacro
,
151 s
=> LibKind
::Other(s
.to_string()),
156 #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
157 pub enum TargetKind
{
162 ExampleLib(Vec
<LibKind
>),
167 impl ser
::Serialize
for TargetKind
{
168 fn serialize
<S
>(&self, s
: S
) -> Result
<S
::Ok
, S
::Error
>
172 use self::TargetKind
::*;
174 Lib(ref kinds
) => s
.collect_seq(kinds
.iter().map(LibKind
::crate_type
)),
175 Bin
=> ["bin"].serialize(s
),
176 ExampleBin
| ExampleLib(_
) => ["example"].serialize(s
),
177 Test
=> ["test"].serialize(s
),
178 CustomBuild
=> ["custom-build"].serialize(s
),
179 Bench
=> ["bench"].serialize(s
),
184 impl fmt
::Debug
for TargetKind
{
185 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
186 use self::TargetKind
::*;
188 Lib(ref kinds
) => kinds
.fmt(f
),
190 ExampleBin
| ExampleLib(_
) => "example".fmt(f
),
191 Test
=> "test".fmt(f
),
192 CustomBuild
=> "custom-build".fmt(f
),
193 Bench
=> "bench".fmt(f
),
199 pub fn description(&self) -> &'
static str {
201 TargetKind
::Lib(..) => "lib",
202 TargetKind
::Bin
=> "bin",
203 TargetKind
::Test
=> "integration-test",
204 TargetKind
::ExampleBin
| TargetKind
::ExampleLib(..) => "example",
205 TargetKind
::Bench
=> "bench",
206 TargetKind
::CustomBuild
=> "build-script",
210 /// Returns whether production of this artifact requires the object files
211 /// from dependencies to be available.
213 /// This only returns `false` when all we're producing is an rlib, otherwise
214 /// it will return `true`.
215 pub fn requires_upstream_objects(&self) -> bool
{
217 TargetKind
::Lib(kinds
) | TargetKind
::ExampleLib(kinds
) => {
218 kinds
.iter().any(|k
| k
.requires_upstream_objects())
225 /// Information about a binary, a library, an example, etc. that is part of the
227 #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
231 // Note that the `src_path` here is excluded from the `Hash` implementation
232 // as it's absolute currently and is otherwise a little too brittle for
233 // causing rebuilds. Instead the hash for the path that we send to the
234 // compiler is handled elsewhere.
235 src_path
: TargetSourcePath
,
236 required_features
: Option
<Vec
<String
>>,
241 harness
: bool
, // whether to use the test harness (--test)
247 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
248 pub enum TargetSourcePath
{
253 impl TargetSourcePath
{
254 pub fn path(&self) -> Option
<&Path
> {
256 TargetSourcePath
::Path(path
) => Some(path
.as_ref()),
257 TargetSourcePath
::Metabuild
=> None
,
261 pub fn is_path(&self) -> bool
{
263 TargetSourcePath
::Path(_
) => true,
269 impl Hash
for TargetSourcePath
{
270 fn hash
<H
: Hasher
>(&self, _
: &mut H
) {
275 impl fmt
::Debug
for TargetSourcePath
{
276 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
278 TargetSourcePath
::Path(path
) => path
.fmt(f
),
279 TargetSourcePath
::Metabuild
=> "metabuild".fmt(f
),
284 impl From
<PathBuf
> for TargetSourcePath
{
285 fn from(path
: PathBuf
) -> Self {
286 assert
!(path
.is_absolute(), "`{}` is not absolute", path
.display());
287 TargetSourcePath
::Path(path
)
292 struct SerializedTarget
<'a
> {
293 /// Is this a `--bin bin`, `--lib`, `--example ex`?
294 /// Serialized as a list of strings for historical reasons.
295 kind
: &'a TargetKind
,
296 /// Corresponds to `--crate-type` compiler attribute.
297 /// See https://doc.rust-lang.org/reference/linkage.html
298 crate_types
: Vec
<&'a
str>,
300 src_path
: Option
<&'a PathBuf
>,
302 #[serde(rename = "required-features", skip_serializing_if = "Option::is_none")]
303 required_features
: Option
<Vec
<&'a
str>>,
307 impl ser
::Serialize
for Target
{
308 fn serialize
<S
: ser
::Serializer
>(&self, s
: S
) -> Result
<S
::Ok
, S
::Error
> {
309 let src_path
= match &self.src_path
{
310 TargetSourcePath
::Path(p
) => Some(p
),
311 // Unfortunately getting the correct path would require access to
312 // target_dir, which is not available here.
313 TargetSourcePath
::Metabuild
=> None
,
317 crate_types
: self.rustc_crate_types(),
320 edition
: &self.edition
.to_string(),
321 required_features
: self
324 .map(|rf
| rf
.iter().map(|s
| &**s
).collect()),
325 doctest
: self.doctest
&& self.doctestable(),
332 impl fmt
::Debug
for Target
{
333 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
334 let (default, default_name
) = {
336 TargetKind
::Lib(kinds
) => {
341 self.src_path().path().unwrap().to_path_buf(),
344 format
!("lib_target({:?}, {:?}, {:?}, {:?})",
345 self.name
, kinds
, self.src_path
, self.edition
),
348 TargetKind
::CustomBuild
=> {
349 match self.src_path
{
350 TargetSourcePath
::Path(ref path
) => {
352 Target
::custom_build_target(
357 format
!("custom_build_target({:?}, {:?}, {:?})",
358 self.name
, path
, self.edition
),
361 TargetSourcePath
::Metabuild
=> {
363 Target
::metabuild_target(&self.name
),
364 format
!("metabuild_target({:?})", self.name
),
370 Target
::new(self.src_path
.clone(), self.edition
),
371 format
!("with_path({:?}, {:?})", self.src_path
, self.edition
),
396 targets
: Vec
<Target
>,
397 exclude
: Vec
<String
>,
398 include
: Vec
<String
>,
399 links
: Option
<String
>,
400 metadata
: ManifestMetadata
,
401 custom_metadata
: Option
<toml
::Value
>,
403 publish
: Option
<Vec
<String
>>,
404 publish_lockfile
: bool
,
405 replace
: Vec
<(PackageIdSpec
, Dependency
)>,
406 patch
: HashMap
<Url
, Vec
<Dependency
>>,
407 workspace
: WorkspaceConfig
,
410 im_a_teapot
: Option
<bool
>,
411 default_run
: Option
<String
>,
412 original
: Rc
<TomlManifest
>,
413 metabuild
: Option
<Vec
<String
>>,
418 warnings
: Warnings
::new(),
439 pub fn dependencies(&self) -> &[Dependency
] {
440 self.summary
.dependencies()
442 pub fn exclude(&self) -> &[String
] {
445 pub fn include(&self) -> &[String
] {
448 pub fn metadata(&self) -> &ManifestMetadata
{
451 pub fn name(&self) -> InternedString
{
452 self.package_id().name()
454 pub fn package_id(&self) -> PackageId
{
455 self.summary
.package_id()
457 pub fn summary(&self) -> &Summary
{
460 pub fn summary_mut(&mut self) -> &mut Summary
{
463 pub fn targets(&self) -> &[Target
] {
466 pub fn targets_mut(&mut self) -> &mut [Target
] {
469 pub fn version(&self) -> &Version
{
470 self.package_id().version()
472 pub fn warnings_mut(&mut self) -> &mut Warnings
{
475 pub fn warnings(&self) -> &Warnings
{
478 pub fn profiles(&self) -> &Profiles
{
481 pub fn publish(&self) -> &Option
<Vec
<String
>> {
484 pub fn replace(&self) -> &[(PackageIdSpec
, Dependency
)] {
487 pub fn original(&self) -> &TomlManifest
{
490 pub fn patch(&self) -> &HashMap
<Url
, Vec
<Dependency
>> {
493 pub fn links(&self) -> Option
<&str> {
494 self.links
.as_ref().map(|s
| &s
[..])
497 pub fn workspace_config(&self) -> &WorkspaceConfig
{
501 pub fn features(&self) -> &Features
{
505 pub fn map_source(self, to_replace
: SourceId
, replace_with
: SourceId
) -> Manifest
{
507 summary
: self.summary
.map_source(to_replace
, replace_with
),
512 pub fn feature_gate(&self) -> CargoResult
<()> {
513 if self.im_a_teapot
.is_some() {
515 .require(Feature
::test_dummy_unstable())
518 "the `im-a-teapot` manifest key is unstable and may \
519 not work properly in England"
527 // Just a helper function to test out `-Z` flags on Cargo
528 pub fn print_teapot(&self, config
: &Config
) {
529 if let Some(teapot
) = self.im_a_teapot
{
530 if config
.cli_unstable().print_im_a_teapot
{
531 println
!("im-a-teapot = {}", teapot
);
536 pub fn edition(&self) -> Edition
{
540 pub fn custom_metadata(&self) -> Option
<&toml
::Value
> {
541 self.custom_metadata
.as_ref()
544 pub fn default_run(&self) -> Option
<&str> {
545 self.default_run
.as_ref().map(|s
| &s
[..])
548 pub fn metabuild(&self) -> Option
<&Vec
<String
>> {
549 self.metabuild
.as_ref()
552 pub fn metabuild_path(&self, target_dir
: Filesystem
) -> PathBuf
{
553 let hash
= short_hash(&self.package_id());
555 .into_path_unlocked()
557 .join(format
!("metabuild-{}-{}.rs", self.name(), hash
))
561 impl VirtualManifest
{
563 replace
: Vec
<(PackageIdSpec
, Dependency
)>,
564 patch
: HashMap
<Url
, Vec
<Dependency
>>,
565 workspace
: WorkspaceConfig
,
568 ) -> VirtualManifest
{
574 warnings
: Warnings
::new(),
579 pub fn replace(&self) -> &[(PackageIdSpec
, Dependency
)] {
583 pub fn patch(&self) -> &HashMap
<Url
, Vec
<Dependency
>> {
587 pub fn workspace_config(&self) -> &WorkspaceConfig
{
591 pub fn profiles(&self) -> &Profiles
{
595 pub fn warnings_mut(&mut self) -> &mut Warnings
{
599 pub fn warnings(&self) -> &Warnings
{
603 pub fn features(&self) -> &Features
{
609 fn new(src_path
: TargetSourcePath
, edition
: Edition
) -> Target
{
611 kind
: TargetKind
::Bin
,
614 required_features
: None
,
626 fn with_path(src_path
: PathBuf
, edition
: Edition
) -> Target
{
627 Target
::new(TargetSourcePath
::from(src_path
), edition
)
632 crate_targets
: Vec
<LibKind
>,
637 kind
: TargetKind
::Lib(crate_targets
),
638 name
: name
.to_string(),
641 ..Target
::with_path(src_path
, edition
)
648 required_features
: Option
<Vec
<String
>>,
652 kind
: TargetKind
::Bin
,
653 name
: name
.to_string(),
656 ..Target
::with_path(src_path
, edition
)
660 /// Builds a `Target` corresponding to the `build = "build.rs"` entry.
661 pub fn custom_build_target(name
: &str, src_path
: PathBuf
, edition
: Edition
) -> Target
{
663 kind
: TargetKind
::CustomBuild
,
664 name
: name
.to_string(),
668 ..Target
::with_path(src_path
, edition
)
672 pub fn metabuild_target(name
: &str) -> Target
{
674 kind
: TargetKind
::CustomBuild
,
675 name
: name
.to_string(),
679 ..Target
::new(TargetSourcePath
::Metabuild
, Edition
::Edition2018
)
683 pub fn example_target(
685 crate_targets
: Vec
<LibKind
>,
687 required_features
: Option
<Vec
<String
>>,
690 let kind
= if crate_targets
.is_empty()
693 .all(|t
| *t
== LibKind
::Other("bin".into()))
695 TargetKind
::ExampleBin
697 TargetKind
::ExampleLib(crate_targets
)
702 name
: name
.to_string(),
706 ..Target
::with_path(src_path
, edition
)
713 required_features
: Option
<Vec
<String
>>,
717 kind
: TargetKind
::Test
,
718 name
: name
.to_string(),
721 ..Target
::with_path(src_path
, edition
)
728 required_features
: Option
<Vec
<String
>>,
732 kind
: TargetKind
::Bench
,
733 name
: name
.to_string(),
736 ..Target
::with_path(src_path
, edition
)
740 pub fn name(&self) -> &str {
743 pub fn crate_name(&self) -> String
{
744 self.name
.replace("-", "_")
746 pub fn src_path(&self) -> &TargetSourcePath
{
749 pub fn set_src_path(&mut self, src_path
: TargetSourcePath
) {
750 self.src_path
= src_path
;
752 pub fn required_features(&self) -> Option
<&Vec
<String
>> {
753 self.required_features
.as_ref()
755 pub fn kind(&self) -> &TargetKind
{
758 pub fn kind_mut(&mut self) -> &mut TargetKind
{
761 pub fn tested(&self) -> bool
{
764 pub fn harness(&self) -> bool
{
767 pub fn documented(&self) -> bool
{
770 // A plugin, proc-macro, or build-script.
771 pub fn for_host(&self) -> bool
{
774 pub fn proc_macro(&self) -> bool
{
777 pub fn edition(&self) -> Edition
{
780 pub fn benched(&self) -> bool
{
783 pub fn doctested(&self) -> bool
{
787 pub fn doctestable(&self) -> bool
{
789 TargetKind
::Lib(ref kinds
) => kinds
791 .any(|k
| *k
== LibKind
::Rlib
|| *k
== LibKind
::Lib
|| *k
== LibKind
::ProcMacro
),
796 pub fn allows_underscores(&self) -> bool
{
797 self.is_bin() || self.is_example() || self.is_custom_build()
800 pub fn is_lib(&self) -> bool
{
802 TargetKind
::Lib(_
) => true,
807 pub fn is_dylib(&self) -> bool
{
809 TargetKind
::Lib(ref libs
) => libs
.iter().any(|l
| *l
== LibKind
::Dylib
),
814 pub fn is_cdylib(&self) -> bool
{
815 let libs
= match self.kind
{
816 TargetKind
::Lib(ref libs
) => libs
,
819 libs
.iter().any(|l
| match *l
{
820 LibKind
::Other(ref s
) => s
== "cdylib",
825 /// Returns whether this target produces an artifact which can be linked
826 /// into a Rust crate.
828 /// This only returns true for certain kinds of libraries.
829 pub fn linkable(&self) -> bool
{
831 TargetKind
::Lib(ref kinds
) => kinds
.iter().any(|k
| k
.linkable()),
836 pub fn is_bin(&self) -> bool
{
837 self.kind
== TargetKind
::Bin
840 pub fn is_example(&self) -> bool
{
842 TargetKind
::ExampleBin
| TargetKind
::ExampleLib(..) => true,
847 /// Returns `true` if it is a binary or executable example.
848 /// NOTE: Tests are `false`!
849 pub fn is_executable(&self) -> bool
{
850 self.is_bin() || self.is_exe_example()
853 /// Returns `true` if it is an executable example.
854 pub fn is_exe_example(&self) -> bool
{
855 // Needed for --all-examples in contexts where only runnable examples make sense
857 TargetKind
::ExampleBin
=> true,
862 pub fn is_test(&self) -> bool
{
863 self.kind
== TargetKind
::Test
865 pub fn is_bench(&self) -> bool
{
866 self.kind
== TargetKind
::Bench
868 pub fn is_custom_build(&self) -> bool
{
869 self.kind
== TargetKind
::CustomBuild
872 /// Returns the arguments suitable for `--crate-type` to pass to rustc.
873 pub fn rustc_crate_types(&self) -> Vec
<&str> {
875 TargetKind
::Lib(ref kinds
) | TargetKind
::ExampleLib(ref kinds
) => {
876 kinds
.iter().map(LibKind
::crate_type
).collect()
878 TargetKind
::CustomBuild
881 | TargetKind
::ExampleBin
882 | TargetKind
::Bin
=> vec
!["bin"],
886 pub fn can_lto(&self) -> bool
{
888 TargetKind
::Lib(ref v
) => {
889 !v
.contains(&LibKind
::Rlib
)
890 && !v
.contains(&LibKind
::Dylib
)
891 && !v
.contains(&LibKind
::Lib
)
897 pub fn set_tested(&mut self, tested
: bool
) -> &mut Target
{
898 self.tested
= tested
;
901 pub fn set_benched(&mut self, benched
: bool
) -> &mut Target
{
902 self.benched
= benched
;
905 pub fn set_doctest(&mut self, doctest
: bool
) -> &mut Target
{
906 self.doctest
= doctest
;
909 pub fn set_for_host(&mut self, for_host
: bool
) -> &mut Target
{
910 self.for_host
= for_host
;
913 pub fn set_proc_macro(&mut self, proc_macro
: bool
) -> &mut Target
{
914 self.proc_macro
= proc_macro
;
917 pub fn set_edition(&mut self, edition
: Edition
) -> &mut Target
{
918 self.edition
= edition
;
921 pub fn set_harness(&mut self, harness
: bool
) -> &mut Target
{
922 self.harness
= harness
;
925 pub fn set_doc(&mut self, doc
: bool
) -> &mut Target
{
930 pub fn description_named(&self) -> String
{
932 TargetKind
::Lib(..) => "lib".to_string(),
933 TargetKind
::Bin
=> format
!("bin \"{}\"", self.name()),
934 TargetKind
::Test
=> format
!("test \"{}\"", self.name()),
935 TargetKind
::Bench
=> format
!("bench \"{}\"", self.name()),
936 TargetKind
::ExampleLib(..) | TargetKind
::ExampleBin
=> {
937 format
!("example \"{}\"", self.name())
939 TargetKind
::CustomBuild
=> "custom-build".to_string(),
944 impl fmt
::Display
for Target
{
945 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
947 TargetKind
::Lib(..) => write
!(f
, "Target(lib)"),
948 TargetKind
::Bin
=> write
!(f
, "Target(bin: {})", self.name
),
949 TargetKind
::Test
=> write
!(f
, "Target(test: {})", self.name
),
950 TargetKind
::Bench
=> write
!(f
, "Target(bench: {})", self.name
),
951 TargetKind
::ExampleBin
| TargetKind
::ExampleLib(..) => {
952 write
!(f
, "Target(example: {})", self.name
)
954 TargetKind
::CustomBuild
=> write
!(f
, "Target(script)"),
960 fn new() -> Warnings
{
964 pub fn add_warning(&mut self, s
: String
) {
965 self.0.push(DelayedWarning
{
971 pub fn add_critical_warning(&mut self, s
: String
) {
972 self.0.push(DelayedWarning
{
978 pub fn warnings(&self) -> &[DelayedWarning
] {