blob: 64c8dec2bbf8aae8ab648e9199c94f5e8e098a85 [file] [log] [blame]
use std::collections::{BTreeMap, HashMap};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::sync::Arc;
use anyhow::Context as _;
use cargo_util_schemas::manifest::RustVersion;
use cargo_util_schemas::manifest::{TomlManifest, TomlProfiles};
use semver::Version;
use serde::ser;
use serde::Serialize;
use url::Url;
use crate::core::compiler::rustdoc::RustdocScrapeExamples;
use crate::core::compiler::{CompileKind, CrateType};
use crate::core::resolver::ResolveBehavior;
use crate::core::{Dependency, PackageId, PackageIdSpec, SourceId, Summary};
use crate::core::{Edition, Feature, Features, WorkspaceConfig};
use crate::util::errors::*;
use crate::util::interning::InternedString;
use crate::util::{short_hash, Filesystem, GlobalContext};
pub enum EitherManifest {
Real(Manifest),
Virtual(VirtualManifest),
}
impl EitherManifest {
pub(crate) fn workspace_config(&self) -> &WorkspaceConfig {
match *self {
EitherManifest::Real(ref r) => r.workspace_config(),
EitherManifest::Virtual(ref v) => v.workspace_config(),
}
}
}
/// Contains all the information about a package, as loaded from a `Cargo.toml`.
///
/// This is deserialized using the [`TomlManifest`] type.
#[derive(Clone, Debug)]
pub struct Manifest {
// alternate forms of manifests:
contents: Rc<String>,
document: Rc<toml_edit::ImDocument<String>>,
resolved_toml: Rc<TomlManifest>,
summary: Summary,
// this form of manifest:
targets: Vec<Target>,
default_kind: Option<CompileKind>,
forced_kind: Option<CompileKind>,
links: Option<String>,
warnings: Warnings,
exclude: Vec<String>,
include: Vec<String>,
metadata: ManifestMetadata,
custom_metadata: Option<toml::Value>,
profiles: Option<TomlProfiles>,
publish: Option<Vec<String>>,
replace: Vec<(PackageIdSpec, Dependency)>,
patch: HashMap<Url, Vec<Dependency>>,
workspace: WorkspaceConfig,
unstable_features: Features,
edition: Edition,
rust_version: Option<RustVersion>,
im_a_teapot: Option<bool>,
default_run: Option<String>,
metabuild: Option<Vec<String>>,
resolve_behavior: Option<ResolveBehavior>,
lint_rustflags: Vec<String>,
embedded: bool,
}
/// When parsing `Cargo.toml`, some warnings should silenced
/// if the manifest comes from a dependency. `ManifestWarning`
/// allows this delayed emission of warnings.
#[derive(Clone, Debug)]
pub struct DelayedWarning {
pub message: String,
pub is_critical: bool,
}
#[derive(Clone, Debug)]
pub struct Warnings(Vec<DelayedWarning>);
#[derive(Clone, Debug)]
pub struct VirtualManifest {
replace: Vec<(PackageIdSpec, Dependency)>,
patch: HashMap<Url, Vec<Dependency>>,
workspace: WorkspaceConfig,
profiles: Option<TomlProfiles>,
warnings: Warnings,
features: Features,
resolve_behavior: Option<ResolveBehavior>,
}
/// General metadata about a package which is just blindly uploaded to the
/// registry.
///
/// Note that many of these fields can contain invalid values such as the
/// homepage, repository, documentation, or license. These fields are not
/// validated by cargo itself, but rather it is up to the registry when uploaded
/// to validate these fields. Cargo will itself accept any valid TOML
/// specification for these values.
#[derive(PartialEq, Clone, Debug)]
pub struct ManifestMetadata {
pub authors: Vec<String>,
pub keywords: Vec<String>,
pub categories: Vec<String>,
pub license: Option<String>,
pub license_file: Option<String>,
pub description: Option<String>, // Not in Markdown
pub readme: Option<String>, // File, not contents
pub homepage: Option<String>, // URL
pub repository: Option<String>, // URL
pub documentation: Option<String>, // URL
pub badges: BTreeMap<String, BTreeMap<String, String>>,
pub links: Option<String>,
pub rust_version: Option<RustVersion>,
}
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum TargetKind {
Lib(Vec<CrateType>),
Bin,
Test,
Bench,
ExampleLib(Vec<CrateType>),
ExampleBin,
CustomBuild,
}
impl ser::Serialize for TargetKind {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
use self::TargetKind::*;
match self {
Lib(kinds) => s.collect_seq(kinds.iter().map(|t| t.to_string())),
Bin => ["bin"].serialize(s),
ExampleBin | ExampleLib(_) => ["example"].serialize(s),
Test => ["test"].serialize(s),
CustomBuild => ["custom-build"].serialize(s),
Bench => ["bench"].serialize(s),
}
}
}
impl fmt::Debug for TargetKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::TargetKind::*;
match *self {
Lib(ref kinds) => kinds.fmt(f),
Bin => "bin".fmt(f),
ExampleBin | ExampleLib(_) => "example".fmt(f),
Test => "test".fmt(f),
CustomBuild => "custom-build".fmt(f),
Bench => "bench".fmt(f),
}
}
}
impl TargetKind {
pub fn description(&self) -> &'static str {
match self {
TargetKind::Lib(..) => "lib",
TargetKind::Bin => "bin",
TargetKind::Test => "integration-test",
TargetKind::ExampleBin | TargetKind::ExampleLib(..) => "example",
TargetKind::Bench => "bench",
TargetKind::CustomBuild => "build-script",
}
}
/// Returns whether production of this artifact requires the object files
/// from dependencies to be available.
///
/// This only returns `false` when all we're producing is an rlib, otherwise
/// it will return `true`.
pub fn requires_upstream_objects(&self) -> bool {
match self {
TargetKind::Lib(kinds) | TargetKind::ExampleLib(kinds) => {
kinds.iter().any(|k| k.requires_upstream_objects())
}
_ => true,
}
}
/// Returns the arguments suitable for `--crate-type` to pass to rustc.
pub fn rustc_crate_types(&self) -> Vec<CrateType> {
match self {
TargetKind::Lib(kinds) | TargetKind::ExampleLib(kinds) => kinds.clone(),
TargetKind::CustomBuild
| TargetKind::Bench
| TargetKind::Test
| TargetKind::ExampleBin
| TargetKind::Bin => vec![CrateType::Bin],
}
}
}
/// Information about a binary, a library, an example, etc. that is part of the
/// package.
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Target {
inner: Arc<TargetInner>,
}
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
struct TargetInner {
kind: TargetKind,
name: String,
// Note that `bin_name` is used for the cargo-feature `different_binary_name`
bin_name: Option<String>,
// Note that the `src_path` here is excluded from the `Hash` implementation
// as it's absolute currently and is otherwise a little too brittle for
// causing rebuilds. Instead the hash for the path that we send to the
// compiler is handled elsewhere.
src_path: TargetSourcePath,
required_features: Option<Vec<String>>,
tested: bool,
benched: bool,
doc: bool,
doctest: bool,
harness: bool, // whether to use the test harness (--test)
for_host: bool,
proc_macro: bool,
edition: Edition,
doc_scrape_examples: RustdocScrapeExamples,
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum TargetSourcePath {
Path(PathBuf),
Metabuild,
}
impl TargetSourcePath {
pub fn path(&self) -> Option<&Path> {
match self {
TargetSourcePath::Path(path) => Some(path.as_ref()),
TargetSourcePath::Metabuild => None,
}
}
pub fn is_path(&self) -> bool {
matches!(self, TargetSourcePath::Path(_))
}
}
impl Hash for TargetSourcePath {
fn hash<H: Hasher>(&self, _: &mut H) {
// ...
}
}
impl fmt::Debug for TargetSourcePath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TargetSourcePath::Path(path) => path.fmt(f),
TargetSourcePath::Metabuild => "metabuild".fmt(f),
}
}
}
impl From<PathBuf> for TargetSourcePath {
fn from(path: PathBuf) -> Self {
assert!(path.is_absolute(), "`{}` is not absolute", path.display());
TargetSourcePath::Path(path)
}
}
#[derive(Serialize)]
struct SerializedTarget<'a> {
/// Is this a `--bin bin`, `--lib`, `--example ex`?
/// Serialized as a list of strings for historical reasons.
kind: &'a TargetKind,
/// Corresponds to `--crate-type` compiler attribute.
/// See <https://doc.rust-lang.org/reference/linkage.html>
crate_types: Vec<CrateType>,
name: &'a str,
src_path: Option<&'a PathBuf>,
edition: &'a str,
#[serde(rename = "required-features", skip_serializing_if = "Option::is_none")]
required_features: Option<Vec<&'a str>>,
/// Whether docs should be built for the target via `cargo doc`
/// See <https://doc.rust-lang.org/cargo/commands/cargo-doc.html#target-selection>
doc: bool,
doctest: bool,
/// Whether tests should be run for the target (`test` field in `Cargo.toml`)
test: bool,
}
impl ser::Serialize for Target {
fn serialize<S: ser::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
let src_path = match self.src_path() {
TargetSourcePath::Path(p) => Some(p),
// Unfortunately getting the correct path would require access to
// target_dir, which is not available here.
TargetSourcePath::Metabuild => None,
};
SerializedTarget {
kind: self.kind(),
crate_types: self.rustc_crate_types(),
name: self.name(),
src_path,
edition: &self.edition().to_string(),
required_features: self
.required_features()
.map(|rf| rf.iter().map(|s| s.as_str()).collect()),
doc: self.documented(),
doctest: self.doctested() && self.doctestable(),
test: self.tested(),
}
.serialize(s)
}
}
impl fmt::Debug for Target {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
compact_debug! {
impl fmt::Debug for TargetInner {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (default, default_name) = {
match &self.kind {
TargetKind::Lib(kinds) => {
(
Target::lib_target(
&self.name,
kinds.clone(),
self.src_path.path().unwrap().to_path_buf(),
self.edition,
).inner,
format!("lib_target({:?}, {:?}, {:?}, {:?})",
self.name, kinds, self.src_path, self.edition),
)
}
TargetKind::CustomBuild => {
match self.src_path {
TargetSourcePath::Path(ref path) => {
(
Target::custom_build_target(
&self.name,
path.to_path_buf(),
self.edition,
).inner,
format!("custom_build_target({:?}, {:?}, {:?})",
self.name, path, self.edition),
)
}
TargetSourcePath::Metabuild => {
(
Target::metabuild_target(&self.name).inner,
format!("metabuild_target({:?})", self.name),
)
}
}
}
_ => (
Target::new(self.src_path.clone(), self.edition).inner,
format!("with_path({:?}, {:?})", self.src_path, self.edition),
),
}
};
[debug_the_fields(
kind
name
bin_name
src_path
required_features
tested
benched
doc
doctest
harness
for_host
proc_macro
edition
doc_scrape_examples
)]
}
}
}
impl Manifest {
pub fn new(
contents: Rc<String>,
document: Rc<toml_edit::ImDocument<String>>,
resolved_toml: Rc<TomlManifest>,
summary: Summary,
default_kind: Option<CompileKind>,
forced_kind: Option<CompileKind>,
targets: Vec<Target>,
exclude: Vec<String>,
include: Vec<String>,
links: Option<String>,
metadata: ManifestMetadata,
custom_metadata: Option<toml::Value>,
profiles: Option<TomlProfiles>,
publish: Option<Vec<String>>,
replace: Vec<(PackageIdSpec, Dependency)>,
patch: HashMap<Url, Vec<Dependency>>,
workspace: WorkspaceConfig,
unstable_features: Features,
edition: Edition,
rust_version: Option<RustVersion>,
im_a_teapot: Option<bool>,
default_run: Option<String>,
metabuild: Option<Vec<String>>,
resolve_behavior: Option<ResolveBehavior>,
lint_rustflags: Vec<String>,
embedded: bool,
) -> Manifest {
Manifest {
contents,
document,
resolved_toml,
summary,
default_kind,
forced_kind,
targets,
warnings: Warnings::new(),
exclude,
include,
links,
metadata,
custom_metadata,
profiles,
publish,
replace,
patch,
workspace,
unstable_features,
edition,
rust_version,
im_a_teapot,
default_run,
metabuild,
resolve_behavior,
lint_rustflags,
embedded,
}
}
/// The raw contents of the original TOML
pub fn contents(&self) -> &str {
self.contents.as_str()
}
/// Collection of spans for the original TOML
pub fn document(&self) -> &toml_edit::ImDocument<String> {
&self.document
}
/// The [`TomlManifest`] with all fields expanded
pub fn resolved_toml(&self) -> &TomlManifest {
&self.resolved_toml
}
pub fn summary(&self) -> &Summary {
&self.summary
}
pub fn summary_mut(&mut self) -> &mut Summary {
&mut self.summary
}
pub fn dependencies(&self) -> &[Dependency] {
self.summary.dependencies()
}
pub fn default_kind(&self) -> Option<CompileKind> {
self.default_kind
}
pub fn forced_kind(&self) -> Option<CompileKind> {
self.forced_kind
}
pub fn exclude(&self) -> &[String] {
&self.exclude
}
pub fn include(&self) -> &[String] {
&self.include
}
pub fn metadata(&self) -> &ManifestMetadata {
&self.metadata
}
pub fn name(&self) -> InternedString {
self.package_id().name()
}
pub fn package_id(&self) -> PackageId {
self.summary.package_id()
}
pub fn targets(&self) -> &[Target] {
&self.targets
}
// It is used by cargo-c, please do not remove it
pub fn targets_mut(&mut self) -> &mut [Target] {
&mut self.targets
}
pub fn version(&self) -> &Version {
self.package_id().version()
}
pub fn warnings_mut(&mut self) -> &mut Warnings {
&mut self.warnings
}
pub fn warnings(&self) -> &Warnings {
&self.warnings
}
pub fn profiles(&self) -> Option<&TomlProfiles> {
self.profiles.as_ref()
}
pub fn publish(&self) -> &Option<Vec<String>> {
&self.publish
}
pub fn replace(&self) -> &[(PackageIdSpec, Dependency)] {
&self.replace
}
pub fn patch(&self) -> &HashMap<Url, Vec<Dependency>> {
&self.patch
}
pub fn links(&self) -> Option<&str> {
self.links.as_deref()
}
pub fn is_embedded(&self) -> bool {
self.embedded
}
pub fn workspace_config(&self) -> &WorkspaceConfig {
&self.workspace
}
/// Unstable, nightly features that are enabled in this manifest.
pub fn unstable_features(&self) -> &Features {
&self.unstable_features
}
/// The style of resolver behavior to use, declared with the `resolver` field.
///
/// Returns `None` if it is not specified.
pub fn resolve_behavior(&self) -> Option<ResolveBehavior> {
self.resolve_behavior
}
/// `RUSTFLAGS` from the `[lints]` table
pub fn lint_rustflags(&self) -> &[String] {
self.lint_rustflags.as_slice()
}
pub fn map_source(self, to_replace: SourceId, replace_with: SourceId) -> Manifest {
Manifest {
summary: self.summary.map_source(to_replace, replace_with),
..self
}
}
pub fn feature_gate(&self) -> CargoResult<()> {
if self.im_a_teapot.is_some() {
self.unstable_features
.require(Feature::test_dummy_unstable())
.with_context(|| {
"the `im-a-teapot` manifest key is unstable and may \
not work properly in England"
})?;
}
if self.default_kind.is_some() || self.forced_kind.is_some() {
self.unstable_features
.require(Feature::per_package_target())
.with_context(|| {
"the `package.default-target` and `package.forced-target` \
manifest keys are unstable and may not work properly"
})?;
}
Ok(())
}
// Just a helper function to test out `-Z` flags on Cargo
pub fn print_teapot(&self, gctx: &GlobalContext) {
if let Some(teapot) = self.im_a_teapot {
if gctx.cli_unstable().print_im_a_teapot {
crate::drop_println!(gctx, "im-a-teapot = {}", teapot);
}
}
}
pub fn edition(&self) -> Edition {
self.edition
}
pub fn rust_version(&self) -> Option<&RustVersion> {
self.rust_version.as_ref()
}
pub fn custom_metadata(&self) -> Option<&toml::Value> {
self.custom_metadata.as_ref()
}
pub fn default_run(&self) -> Option<&str> {
self.default_run.as_deref()
}
pub fn metabuild(&self) -> Option<&Vec<String>> {
self.metabuild.as_ref()
}
pub fn metabuild_path(&self, target_dir: Filesystem) -> PathBuf {
let hash = short_hash(&self.package_id());
target_dir
.into_path_unlocked()
.join(".metabuild")
.join(format!("metabuild-{}-{}.rs", self.name(), hash))
}
}
impl VirtualManifest {
pub fn new(
replace: Vec<(PackageIdSpec, Dependency)>,
patch: HashMap<Url, Vec<Dependency>>,
workspace: WorkspaceConfig,
profiles: Option<TomlProfiles>,
features: Features,
resolve_behavior: Option<ResolveBehavior>,
) -> VirtualManifest {
VirtualManifest {
replace,
patch,
workspace,
profiles,
warnings: Warnings::new(),
features,
resolve_behavior,
}
}
pub fn replace(&self) -> &[(PackageIdSpec, Dependency)] {
&self.replace
}
pub fn patch(&self) -> &HashMap<Url, Vec<Dependency>> {
&self.patch
}
pub fn workspace_config(&self) -> &WorkspaceConfig {
&self.workspace
}
pub fn profiles(&self) -> Option<&TomlProfiles> {
self.profiles.as_ref()
}
pub fn warnings_mut(&mut self) -> &mut Warnings {
&mut self.warnings
}
pub fn warnings(&self) -> &Warnings {
&self.warnings
}
pub fn unstable_features(&self) -> &Features {
&self.features
}
/// The style of resolver behavior to use, declared with the `resolver` field.
///
/// Returns `None` if it is not specified.
pub fn resolve_behavior(&self) -> Option<ResolveBehavior> {
self.resolve_behavior
}
}
impl Target {
fn new(src_path: TargetSourcePath, edition: Edition) -> Target {
Target {
inner: Arc::new(TargetInner {
kind: TargetKind::Bin,
name: String::new(),
bin_name: None,
src_path,
required_features: None,
doc: false,
doctest: false,
harness: true,
for_host: false,
proc_macro: false,
doc_scrape_examples: RustdocScrapeExamples::Unset,
edition,
tested: true,
benched: true,
}),
}
}
fn with_path(src_path: PathBuf, edition: Edition) -> Target {
Target::new(TargetSourcePath::from(src_path), edition)
}
pub fn lib_target(
name: &str,
crate_targets: Vec<CrateType>,
src_path: PathBuf,
edition: Edition,
) -> Target {
let mut target = Target::with_path(src_path, edition);
target
.set_kind(TargetKind::Lib(crate_targets))
.set_name(name)
.set_doctest(true)
.set_doc(true);
target
}
pub fn bin_target(
name: &str,
bin_name: Option<String>,
src_path: PathBuf,
required_features: Option<Vec<String>>,
edition: Edition,
) -> Target {
let mut target = Target::with_path(src_path, edition);
target
.set_kind(TargetKind::Bin)
.set_name(name)
.set_binary_name(bin_name)
.set_required_features(required_features)
.set_doc(true);
target
}
/// Builds a `Target` corresponding to the `build = "build.rs"` entry.
pub fn custom_build_target(name: &str, src_path: PathBuf, edition: Edition) -> Target {
let mut target = Target::with_path(src_path, edition);
target
.set_kind(TargetKind::CustomBuild)
.set_name(name)
.set_for_host(true)
.set_benched(false)
.set_tested(false)
.set_doc_scrape_examples(RustdocScrapeExamples::Disabled);
target
}
pub fn metabuild_target(name: &str) -> Target {
let mut target = Target::new(TargetSourcePath::Metabuild, Edition::Edition2018);
target
.set_kind(TargetKind::CustomBuild)
.set_name(name)
.set_for_host(true)
.set_benched(false)
.set_tested(false)
.set_doc_scrape_examples(RustdocScrapeExamples::Disabled);
target
}
pub fn example_target(
name: &str,
crate_targets: Vec<CrateType>,
src_path: PathBuf,
required_features: Option<Vec<String>>,
edition: Edition,
) -> Target {
let kind = if crate_targets.is_empty() || crate_targets.iter().all(|t| *t == CrateType::Bin)
{
TargetKind::ExampleBin
} else {
TargetKind::ExampleLib(crate_targets)
};
let mut target = Target::with_path(src_path, edition);
target
.set_kind(kind)
.set_name(name)
.set_required_features(required_features)
.set_tested(false)
.set_benched(false);
target
}
pub fn test_target(
name: &str,
src_path: PathBuf,
required_features: Option<Vec<String>>,
edition: Edition,
) -> Target {
let mut target = Target::with_path(src_path, edition);
target
.set_kind(TargetKind::Test)
.set_name(name)
.set_required_features(required_features)
.set_benched(false);
target
}
pub fn bench_target(
name: &str,
src_path: PathBuf,
required_features: Option<Vec<String>>,
edition: Edition,
) -> Target {
let mut target = Target::with_path(src_path, edition);
target
.set_kind(TargetKind::Bench)
.set_name(name)
.set_required_features(required_features)
.set_tested(false);
target
}
pub fn name(&self) -> &str {
&self.inner.name
}
pub fn crate_name(&self) -> String {
self.name().replace("-", "_")
}
pub fn src_path(&self) -> &TargetSourcePath {
&self.inner.src_path
}
pub fn set_src_path(&mut self, src_path: TargetSourcePath) {
Arc::make_mut(&mut self.inner).src_path = src_path;
}
pub fn required_features(&self) -> Option<&Vec<String>> {
self.inner.required_features.as_ref()
}
pub fn kind(&self) -> &TargetKind {
&self.inner.kind
}
pub fn tested(&self) -> bool {
self.inner.tested
}
pub fn harness(&self) -> bool {
self.inner.harness
}
pub fn documented(&self) -> bool {
self.inner.doc
}
// A plugin, proc-macro, or build-script.
pub fn for_host(&self) -> bool {
self.inner.for_host
}
pub fn proc_macro(&self) -> bool {
self.inner.proc_macro
}
pub fn edition(&self) -> Edition {
self.inner.edition
}
pub fn doc_scrape_examples(&self) -> RustdocScrapeExamples {
self.inner.doc_scrape_examples
}
pub fn benched(&self) -> bool {
self.inner.benched
}
pub fn doctested(&self) -> bool {
self.inner.doctest
}
pub fn doctestable(&self) -> bool {
match self.kind() {
TargetKind::Lib(ref kinds) => kinds.iter().any(|k| {
*k == CrateType::Rlib || *k == CrateType::Lib || *k == CrateType::ProcMacro
}),
_ => false,
}
}
pub fn is_lib(&self) -> bool {
matches!(self.kind(), TargetKind::Lib(_))
}
pub fn is_dylib(&self) -> bool {
match self.kind() {
TargetKind::Lib(libs) => libs.iter().any(|l| *l == CrateType::Dylib),
_ => false,
}
}
pub fn is_cdylib(&self) -> bool {
match self.kind() {
TargetKind::Lib(libs) => libs.iter().any(|l| *l == CrateType::Cdylib),
_ => false,
}
}
pub fn is_staticlib(&self) -> bool {
match self.kind() {
TargetKind::Lib(libs) => libs.iter().any(|l| *l == CrateType::Staticlib),
_ => false,
}
}
/// Returns whether this target produces an artifact which can be linked
/// into a Rust crate.
///
/// This only returns true for certain kinds of libraries.
pub fn is_linkable(&self) -> bool {
match self.kind() {
TargetKind::Lib(kinds) => kinds.iter().any(|k| k.is_linkable()),
_ => false,
}
}
pub fn is_bin(&self) -> bool {
*self.kind() == TargetKind::Bin
}
pub fn is_example(&self) -> bool {
matches!(
self.kind(),
TargetKind::ExampleBin | TargetKind::ExampleLib(..)
)
}
/// Returns `true` if it is a binary or executable example.
/// NOTE: Tests are `false`!
pub fn is_executable(&self) -> bool {
self.is_bin() || self.is_exe_example()
}
/// Returns `true` if it is an executable example.
pub fn is_exe_example(&self) -> bool {
// Needed for --all-examples in contexts where only runnable examples make sense
matches!(self.kind(), TargetKind::ExampleBin)
}
pub fn is_test(&self) -> bool {
*self.kind() == TargetKind::Test
}
pub fn is_bench(&self) -> bool {
*self.kind() == TargetKind::Bench
}
pub fn is_custom_build(&self) -> bool {
*self.kind() == TargetKind::CustomBuild
}
/// Returns the arguments suitable for `--crate-type` to pass to rustc.
pub fn rustc_crate_types(&self) -> Vec<CrateType> {
self.kind().rustc_crate_types()
}
pub fn set_tested(&mut self, tested: bool) -> &mut Target {
Arc::make_mut(&mut self.inner).tested = tested;
self
}
pub fn set_benched(&mut self, benched: bool) -> &mut Target {
Arc::make_mut(&mut self.inner).benched = benched;
self
}
pub fn set_doctest(&mut self, doctest: bool) -> &mut Target {
Arc::make_mut(&mut self.inner).doctest = doctest;
self
}
pub fn set_for_host(&mut self, for_host: bool) -> &mut Target {
Arc::make_mut(&mut self.inner).for_host = for_host;
self
}
pub fn set_proc_macro(&mut self, proc_macro: bool) -> &mut Target {
Arc::make_mut(&mut self.inner).proc_macro = proc_macro;
self
}
pub fn set_edition(&mut self, edition: Edition) -> &mut Target {
Arc::make_mut(&mut self.inner).edition = edition;
self
}
pub fn set_doc_scrape_examples(
&mut self,
doc_scrape_examples: RustdocScrapeExamples,
) -> &mut Target {
Arc::make_mut(&mut self.inner).doc_scrape_examples = doc_scrape_examples;
self
}
pub fn set_harness(&mut self, harness: bool) -> &mut Target {
Arc::make_mut(&mut self.inner).harness = harness;
self
}
pub fn set_doc(&mut self, doc: bool) -> &mut Target {
Arc::make_mut(&mut self.inner).doc = doc;
self
}
pub fn set_kind(&mut self, kind: TargetKind) -> &mut Target {
Arc::make_mut(&mut self.inner).kind = kind;
self
}
pub fn set_name(&mut self, name: &str) -> &mut Target {
Arc::make_mut(&mut self.inner).name = name.to_string();
self
}
pub fn set_binary_name(&mut self, bin_name: Option<String>) -> &mut Target {
Arc::make_mut(&mut self.inner).bin_name = bin_name;
self
}
pub fn set_required_features(&mut self, required_features: Option<Vec<String>>) -> &mut Target {
Arc::make_mut(&mut self.inner).required_features = required_features;
self
}
pub fn binary_filename(&self) -> Option<String> {
self.inner.bin_name.clone()
}
pub fn description_named(&self) -> String {
match self.kind() {
TargetKind::Lib(..) => "lib".to_string(),
TargetKind::Bin => format!("bin \"{}\"", self.name()),
TargetKind::Test => format!("test \"{}\"", self.name()),
TargetKind::Bench => format!("bench \"{}\"", self.name()),
TargetKind::ExampleLib(..) | TargetKind::ExampleBin => {
format!("example \"{}\"", self.name())
}
TargetKind::CustomBuild => "build script".to_string(),
}
}
}
impl fmt::Display for Target {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.kind() {
TargetKind::Lib(..) => write!(f, "Target(lib)"),
TargetKind::Bin => write!(f, "Target(bin: {})", self.name()),
TargetKind::Test => write!(f, "Target(test: {})", self.name()),
TargetKind::Bench => write!(f, "Target(bench: {})", self.name()),
TargetKind::ExampleBin | TargetKind::ExampleLib(..) => {
write!(f, "Target(example: {})", self.name())
}
TargetKind::CustomBuild => write!(f, "Target(script)"),
}
}
}
impl Warnings {
fn new() -> Warnings {
Warnings(Vec::new())
}
pub fn add_warning(&mut self, s: String) {
self.0.push(DelayedWarning {
message: s,
is_critical: false,
})
}
pub fn add_critical_warning(&mut self, s: String) {
self.0.push(DelayedWarning {
message: s,
is_critical: true,
})
}
pub fn warnings(&self) -> &[DelayedWarning] {
&self.0
}
}