Skip to content

Commit

Permalink
Auto merge of #3667 - jbendig:required_features, r=alexcrichton
Browse files Browse the repository at this point in the history
Added required_features for issue #1570.

Based on PR #2056 by @tsurai and PR #2325 by @JanLikar

I tried to fix most everything that was talked about in the previous pull requests. Docs still need to be updated though.
  • Loading branch information
bors committed Feb 10, 2017
2 parents bbed786 + d43fd2e commit 1b39da7
Show file tree
Hide file tree
Showing 6 changed files with 827 additions and 23 deletions.
19 changes: 15 additions & 4 deletions src/cargo/core/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ pub struct Target {
kind: TargetKind,
name: String,
src_path: PathBuf,
required_features: Option<Vec<String>>,
tested: bool,
benched: bool,
doc: bool,
Expand Down Expand Up @@ -305,6 +306,7 @@ impl Target {
kind: TargetKind::Bin,
name: String::new(),
src_path: src_path,
required_features: None,
doc: false,
doctest: false,
harness: true,
Expand All @@ -326,10 +328,12 @@ impl Target {
}
}

pub fn bin_target(name: &str, src_path: PathBuf) -> Target {
pub fn bin_target(name: &str, src_path: PathBuf,
required_features: Option<Vec<String>>) -> Target {
Target {
kind: TargetKind::Bin,
name: name.to_string(),
required_features: required_features,
doc: true,
..Target::with_path(src_path)
}
Expand All @@ -349,7 +353,8 @@ impl Target {

pub fn example_target(name: &str,
crate_targets: Vec<LibKind>,
src_path: PathBuf) -> Target {
src_path: PathBuf,
required_features: Option<Vec<String>>) -> Target {
let kind = if crate_targets.is_empty() {
TargetKind::ExampleBin
} else {
Expand All @@ -359,24 +364,29 @@ impl Target {
Target {
kind: kind,
name: name.to_string(),
required_features: required_features,
benched: false,
..Target::with_path(src_path)
}
}

pub fn test_target(name: &str, src_path: PathBuf) -> Target {
pub fn test_target(name: &str, src_path: PathBuf,
required_features: Option<Vec<String>>) -> Target {
Target {
kind: TargetKind::Test,
name: name.to_string(),
required_features: required_features,
benched: false,
..Target::with_path(src_path)
}
}

pub fn bench_target(name: &str, src_path: PathBuf) -> Target {
pub fn bench_target(name: &str, src_path: PathBuf,
required_features: Option<Vec<String>>) -> Target {
Target {
kind: TargetKind::Bench,
name: name.to_string(),
required_features: required_features,
tested: false,
..Target::with_path(src_path)
}
Expand All @@ -385,6 +395,7 @@ impl Target {
pub fn name(&self) -> &str { &self.name }
pub fn crate_name(&self) -> String { self.name.replace("-", "_") }
pub fn src_path(&self) -> &Path { &self.src_path }
pub fn required_features(&self) -> Option<&Vec<String>> { self.required_features.as_ref() }
pub fn kind(&self) -> &TargetKind { &self.kind }
pub fn tested(&self) -> bool { self.tested }
pub fn harness(&self) -> bool { self.harness }
Expand Down
65 changes: 50 additions & 15 deletions src/cargo/ops/cargo_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
//! previously compiled dependency
//!

use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::default::Default;
use std::path::PathBuf;
use std::sync::Arc;

Expand Down Expand Up @@ -187,7 +188,8 @@ pub fn compile_ws<'a>(ws: &Workspace<'a>,
}
} else {
let root_package = ws.current()?;
generate_targets(root_package, profiles, mode, filter, release)?;
let all_features = resolve_with_overrides.features(root_package.package_id());
generate_targets(root_package, profiles, mode, filter, all_features, release)?;
pkgids.push(root_package.package_id());
};

Expand All @@ -204,8 +206,9 @@ pub fn compile_ws<'a>(ws: &Workspace<'a>,
panic!("`rustc` and `rustdoc` should not accept multiple `-p` flags")
}
(Some(args), _) => {
let all_features = resolve_with_overrides.features(to_builds[0].package_id());
let targets = generate_targets(to_builds[0], profiles,
mode, filter, release)?;
mode, filter, all_features, release)?;
if targets.len() == 1 {
let (target, profile) = targets[0];
let mut profile = profile.clone();
Expand All @@ -218,8 +221,9 @@ pub fn compile_ws<'a>(ws: &Workspace<'a>,
}
}
(None, Some(args)) => {
let all_features = resolve_with_overrides.features(to_builds[0].package_id());
let targets = generate_targets(to_builds[0], profiles,
mode, filter, release)?;
mode, filter, all_features, release)?;
if targets.len() == 1 {
let (target, profile) = targets[0];
let mut profile = profile.clone();
Expand All @@ -233,8 +237,9 @@ pub fn compile_ws<'a>(ws: &Workspace<'a>,
}
(None, None) => {
for &to_build in to_builds.iter() {
let all_features = resolve_with_overrides.features(to_build.package_id());
let targets = generate_targets(to_build, profiles, mode,
filter, release)?;
filter, all_features, release)?;
package_targets.push((to_build, targets));
}
}
Expand Down Expand Up @@ -313,6 +318,7 @@ fn generate_targets<'a>(pkg: &'a Package,
profiles: &'a Profiles,
mode: CompileMode,
filter: &CompileFilter,
features: Option<&HashSet<String>>,
release: bool)
-> CargoResult<Vec<(&'a Target, &'a Profile)>> {
let build = if release {&profiles.release} else {&profiles.dev};
Expand All @@ -325,13 +331,13 @@ fn generate_targets<'a>(pkg: &'a Package,
CompileMode::Doc { .. } => &profiles.doc,
CompileMode::Doctest => &profiles.doctest,
};
match *filter {
let mut targets = match *filter {
CompileFilter::Everything => {
match mode {
CompileMode::Bench => {
Ok(pkg.targets().iter().filter(|t| t.benched()).map(|t| {
pkg.targets().iter().filter(|t| t.benched()).map(|t| {
(t, profile)
}).collect::<Vec<_>>())
}).collect::<Vec<_>>()
}
CompileMode::Test => {
let deps = if release {
Expand All @@ -352,16 +358,16 @@ fn generate_targets<'a>(pkg: &'a Package,
base.push((t, deps));
}
}
Ok(base)
base
}
CompileMode::Build | CompileMode::Check => {
Ok(pkg.targets().iter().filter(|t| {
pkg.targets().iter().filter(|t| {
t.is_bin() || t.is_lib()
}).map(|t| (t, profile)).collect())
}).map(|t| (t, profile)).collect()
}
CompileMode::Doc { .. } => {
Ok(pkg.targets().iter().filter(|t| t.documented())
.map(|t| (t, profile)).collect())
pkg.targets().iter().filter(|t| t.documented())
.map(|t| (t, profile)).collect()
}
CompileMode::Doctest => {
if let Some(t) = pkg.targets().iter().find(|t| t.is_lib()) {
Expand All @@ -370,7 +376,7 @@ fn generate_targets<'a>(pkg: &'a Package,
}
}

Ok(Vec::new())
Vec::new()
}
}
}
Expand Down Expand Up @@ -409,6 +415,7 @@ fn generate_targets<'a>(pkg: &'a Package,
}
};
debug!("found {} `{}`", desc, name);

targets.push((t, profile));
}
Ok(())
Expand All @@ -418,9 +425,37 @@ fn generate_targets<'a>(pkg: &'a Package,
find(tests, "test", Target::is_test, test)?;
find(benches, "bench", Target::is_bench, &profiles.bench)?;
}
Ok(targets)
targets
}
};

//Collect the targets that are libraries or have all required features available.
let no_features = HashSet::new();
let features = features.unwrap_or(&no_features);
let mut compatible_targets = Vec::with_capacity(targets.len());
for (target, profile) in targets.drain(0..) {
if target.is_lib() || match target.required_features() {
Some(f) => f.iter().all(|f| features.contains(f)),
None => true,
} {
compatible_targets.push((target, profile));
continue;
}

if let CompileFilter::Only { .. } = *filter {
let required_features = target.required_features().unwrap();
let quoted_required_features: Vec<String> = required_features.iter()
.map(|s| format!("`{}`",s))
.collect();
bail!("target `{}` requires the features: {}\n\
Consider enabling them by passing e.g. `--features=\"{}\"`",
target.name(),
quoted_required_features.join(", "),
required_features.join(" "));
}
}

Ok(compatible_targets)
}

/// Parse all config files to learn about build configuration. Currently
Expand Down
4 changes: 4 additions & 0 deletions src/cargo/ops/cargo_install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ pub fn install(root: Option<&str>,
bail!("Binary `{:?}` name can't be serialized into string", name)
}
}).collect::<CargoResult<_>>()?;
if binaries.is_empty() {
bail!("no binaries are available for install using the selected \
features");
}

let metadata = metadata(config, &root)?;
let mut list = read_crate_list(metadata.file())?;
Expand Down
14 changes: 10 additions & 4 deletions src/cargo/util/toml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,7 @@ struct TomlTarget {
plugin: Option<bool>,
proc_macro: Option<bool>,
harness: Option<bool>,
required_features: Option<Vec<String>>,
}

#[derive(RustcDecodable, Clone)]
Expand Down Expand Up @@ -961,6 +962,7 @@ impl TomlTarget {
plugin: None,
proc_macro: None,
harness: None,
required_features: None
}
}

Expand Down Expand Up @@ -1125,7 +1127,8 @@ fn normalize(package_root: &Path,
false => PathValue::Path(Path::new("src").join("main.rs"))
}
});
let mut target = Target::bin_target(&bin.name(), package_root.join(path.to_path()));
let mut target = Target::bin_target(&bin.name(), package_root.join(path.to_path()),
bin.required_features.clone());
configure(bin, &mut target);
dst.push(target);
}
Expand Down Expand Up @@ -1154,7 +1157,8 @@ fn normalize(package_root: &Path,
let mut target = Target::example_target(
&ex.name(),
crate_types,
package_root.join(path.to_path())
package_root.join(path.to_path()),
ex.required_features.clone()
);
configure(ex, &mut target);
dst.push(target);
Expand All @@ -1169,7 +1173,8 @@ fn normalize(package_root: &Path,
PathValue::Path(default(test))
});

let mut target = Target::test_target(&test.name(), package_root.join(path.to_path()));
let mut target = Target::test_target(&test.name(), package_root.join(path.to_path()),
test.required_features.clone());
configure(test, &mut target);
dst.push(target);
}
Expand All @@ -1183,7 +1188,8 @@ fn normalize(package_root: &Path,
PathValue::Path(default(bench))
});

let mut target = Target::bench_target(&bench.name(), package_root.join(path.to_path()));
let mut target = Target::bench_target(&bench.name(), package_root.join(path.to_path()),
bench.required_features.clone());
configure(bench, &mut target);
dst.push(target);
}
Expand Down
18 changes: 18 additions & 0 deletions src/doc/manifest.md
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,24 @@ proc-macro = false
harness = true
```

## The `required-features` field (optional)

The `required-features` field specifies which features must be selected for the
target to be built. This is only relevant for the `[[bin]]`, `[[bench]]`,
`[[test]]`, and `[[example]]` sections, it has no effect on `[lib]`.

```toml
[features]
# ...
postgres = []
sqlite = []
tools = []

[[bin]]
# ...
required-features = ["postgres", "tools"]
```

# Building dynamic or static libraries

If your project produces a library, you can specify which kind of library to
Expand Down
Loading

0 comments on commit 1b39da7

Please sign in to comment.