Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added required_features for issue #1570. #3667

Merged
merged 5 commits into from
Feb 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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