Skip to content
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
44 changes: 32 additions & 12 deletions src/cargo/core/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,18 +107,20 @@ pub enum TargetKind {
Bin,
Test,
Bench,
Example,
ExampleLib(Vec<LibKind>),
ExampleBin,
CustomBuild,
}

impl Encodable for TargetKind {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
match *self {
TargetKind::Lib(ref kinds) => {
kinds.iter().map(|k| k.crate_type()).collect()
TargetKind::Lib(ref kinds) |
TargetKind::ExampleLib(ref kinds) => {
kinds.iter().map(LibKind::crate_type).collect()
}
TargetKind::Bin => vec!["bin"],
TargetKind::Example => vec!["example"],
TargetKind::ExampleBin => vec!["example"],
TargetKind::Test => vec!["test"],
TargetKind::CustomBuild => vec!["custom-build"],
TargetKind::Bench => vec!["bench"],
Expand Down Expand Up @@ -345,9 +347,17 @@ impl Target {
}
}

pub fn example_target(name: &str, src_path: PathBuf) -> Target {
pub fn example_target(name: &str,
crate_targets: Vec<LibKind>,
src_path: PathBuf) -> Target {
let kind = if crate_targets.is_empty() {
TargetKind::ExampleBin
} else {
TargetKind::ExampleLib(crate_targets)
};

Target {
kind: TargetKind::Example,
kind: kind,
name: name.to_string(),
benched: false,
..Target::with_path(src_path)
Expand Down Expand Up @@ -423,21 +433,30 @@ impl Target {
}

pub fn is_bin(&self) -> bool { self.kind == TargetKind::Bin }
pub fn is_example(&self) -> bool { self.kind == TargetKind::Example }

pub fn is_example(&self) -> bool {
match self.kind {
TargetKind::ExampleBin |
TargetKind::ExampleLib(..) => true,
_ => false
}
}

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<&str> {
match self.kind {
TargetKind::Lib(ref kinds) => {
kinds.iter().map(|kind| kind.crate_type()).collect()
},
TargetKind::Lib(ref kinds) |
TargetKind::ExampleLib(ref kinds) => {
kinds.iter().map(LibKind::crate_type).collect()
}
TargetKind::CustomBuild |
TargetKind::Bench |
TargetKind::Test |
TargetKind::Example |
TargetKind::ExampleBin |
TargetKind::Bin => vec!["bin"],
}
}
Expand Down Expand Up @@ -486,7 +505,8 @@ impl fmt::Display for Target {
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::Example => write!(f, "Target(example: {})", self.name),
TargetKind::ExampleBin |
TargetKind::ExampleLib(..) => write!(f, "Target(example: {})", self.name),
TargetKind::CustomBuild => write!(f, "Target(script)"),
}
}
Expand Down
8 changes: 5 additions & 3 deletions src/cargo/core/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::path::{Path, PathBuf};

use semver::Version;

use core::{Dependency, Manifest, PackageId, SourceId, Target, TargetKind};
use core::{Dependency, Manifest, PackageId, SourceId, Target};
use core::{Summary, SourceMap};
use ops;
use util::{CargoResult, Config, LazyCell, ChainError, internal, human, lev_distance};
Expand Down Expand Up @@ -94,10 +94,12 @@ impl Package {
self.targets().iter().any(|t| t.is_custom_build())
}

pub fn find_closest_target(&self, target: &str, kind: TargetKind) -> Option<&Target> {
pub fn find_closest_target(&self,
target: &str,
is_expected_kind: fn(&Target)-> bool) -> Option<&Target> {
let targets = self.targets();

let matches = targets.iter().filter(|t| *t.kind() == kind)
let matches = targets.iter().filter(|t| is_expected_kind(t))
.map(|t| (lev_distance(target, t.name()), t))
.filter(|&(d, _)| d < 4);
matches.min_by_key(|t| t.0).map(|t| t.1)
Expand Down
20 changes: 12 additions & 8 deletions src/cargo/ops/cargo_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,8 @@ impl<'a> CompileFilter<'a> {
TargetKind::Bin => bins,
TargetKind::Test => tests,
TargetKind::Bench => benches,
TargetKind::Example => examples,
TargetKind::ExampleBin |
TargetKind::ExampleLib(..) => examples,
TargetKind::Lib(..) => return lib,
TargetKind::CustomBuild => return false,
};
Expand Down Expand Up @@ -385,15 +386,18 @@ fn generate_targets<'a>(pkg: &'a Package,
}

{
let mut find = |names: &[String], desc, kind, profile| {
let mut find = |names: &[String],
desc,
is_expected_kind: fn(&Target) -> bool,
profile| {
for name in names {
let target = pkg.targets().iter().find(|t| {
t.name() == *name && *t.kind() == kind
t.name() == *name && is_expected_kind(t)
});
let t = match target {
Some(t) => t,
None => {
let suggestion = pkg.find_closest_target(name, kind);
let suggestion = pkg.find_closest_target(name, is_expected_kind);
match suggestion {
Some(s) => {
let suggested_name = s.name();
Expand All @@ -409,10 +413,10 @@ fn generate_targets<'a>(pkg: &'a Package,
}
Ok(())
};
find(bins, "bin", TargetKind::Bin, profile)?;
find(examples, "example", TargetKind::Example, build)?;
find(tests, "test", TargetKind::Test, test)?;
find(benches, "bench", TargetKind::Bench, &profiles.bench)?;
find(bins, "bin", Target::is_bin, profile)?;
find(examples, "example", Target::is_example, build)?;
find(tests, "test", Target::is_test, test)?;
find(benches, "bench", Target::is_bench, &profiles.bench)?;
}
Ok(targets)
}
Expand Down
14 changes: 9 additions & 5 deletions src/cargo/ops/cargo_rustc/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
for unit in units {
self.visit_crate_type(unit, &mut crate_types)?;
}
debug!("probe_target_info: crate_types={:?}", crate_types);
self.probe_target_info_kind(&crate_types, Kind::Target)?;
if self.requested_target().is_none() {
self.host_info = self.target_info.clone();
Expand Down Expand Up @@ -525,19 +526,22 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
};

match *unit.target.kind() {
TargetKind::Example |
TargetKind::Bin |
TargetKind::CustomBuild |
TargetKind::ExampleBin |
TargetKind::Bench |
TargetKind::Test => {
add("bin", false)?;
}
TargetKind::Lib(..) if unit.profile.test => {
TargetKind::Lib(..) |
TargetKind::ExampleLib(..)
if unit.profile.test => {
add("bin", false)?;
}
TargetKind::Lib(ref libs) => {
for lib in libs {
add(lib.crate_type(), lib.linkable())?;
TargetKind::ExampleLib(ref kinds) |
TargetKind::Lib(ref kinds) => {
for kind in kinds {
add(kind.crate_type(), kind.linkable())?;
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/cargo/ops/cargo_rustc/fingerprint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,8 @@ fn filename(cx: &mut Context, unit: &Unit) -> String {
TargetKind::Lib(..) => "lib",
TargetKind::Bin => "bin",
TargetKind::Test => "integration-test",
TargetKind::Example => "example",
TargetKind::ExampleBin |
TargetKind::ExampleLib(..) => "example",
TargetKind::Bench => "bench",
TargetKind::CustomBuild => "build-script",
};
Expand Down
11 changes: 10 additions & 1 deletion src/cargo/util/toml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1169,7 +1169,16 @@ fn normalize(package_root: &Path,
PathValue::Path(default(ex))
});

let mut target = Target::example_target(&ex.name(), package_root.join(path.to_path()));
let crate_types = match ex.crate_type {
Some(ref kinds) => kinds.iter().map(|s| LibKind::from_str(s)).collect(),
None => Vec::new()
};

let mut target = Target::example_target(
&ex.name(),
crate_types,
package_root.join(path.to_path())
);
configure(ex, &mut target);
dst.push(target);
}
Expand Down
84 changes: 84 additions & 0 deletions tests/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1890,6 +1890,90 @@ fn cargo_platform_specific_dependency_wrong_platform() {
assert!(lockfile.contains("bar"))
}

#[test]
fn example_as_lib() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []

[[example]]
name = "ex"
crate-type = ["lib"]
"#)
.file("src/lib.rs", "")
.file("examples/ex.rs", "");

assert_that(p.cargo_process("build").arg("--example=ex"), execs().with_status(0));
assert_that(&p.example_lib("ex", "lib"), existing_file());
}

#[test]
fn example_as_rlib() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []

[[example]]
name = "ex"
crate-type = ["rlib"]
"#)
.file("src/lib.rs", "")
.file("examples/ex.rs", "");

assert_that(p.cargo_process("build").arg("--example=ex"), execs().with_status(0));
assert_that(&p.example_lib("ex", "rlib"), existing_file());
}

#[test]
fn example_as_dylib() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []

[[example]]
name = "ex"
crate-type = ["dylib"]
"#)
.file("src/lib.rs", "")
.file("examples/ex.rs", "");

assert_that(p.cargo_process("build").arg("--example=ex"), execs().with_status(0));
assert_that(&p.example_lib("ex", "dylib"), existing_file());
}

#[test]
fn example_as_proc_macro() {
if !is_nightly() {
return;
}

let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []

[[example]]
name = "ex"
crate-type = ["proc-macro"]
"#)
.file("src/lib.rs", "")
.file("examples/ex.rs", "#![feature(proc_macro)]");

assert_that(p.cargo_process("build").arg("--example=ex"), execs().with_status(0));
assert_that(&p.example_lib("ex", "proc-macro"), existing_file());
}

#[test]
fn example_bin_same_name() {
let p = project("foo")
Expand Down
56 changes: 56 additions & 0 deletions tests/cargotest/support/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,25 @@ impl ProjectBuilder {

pub fn url(&self) -> Url { path2url(self.root()) }

pub fn target_debug_dir(&self) -> PathBuf {
self.build_dir().join("debug")
}

pub fn example_lib(&self, name: &str, kind: &str) -> PathBuf {
let prefix = ProjectBuilder::get_lib_prefix(kind);

let extension = ProjectBuilder::get_lib_extension(kind);

let lib_file_name = format!("{}{}.{}",
prefix,
name,
extension);

self.target_debug_dir()
.join("examples")
.join(&lib_file_name)
}

pub fn bin(&self, b: &str) -> PathBuf {
self.build_dir().join("debug").join(&format!("{}{}", b,
env::consts::EXE_SUFFIX))
Expand Down Expand Up @@ -188,6 +207,43 @@ impl ProjectBuilder {
buffer
}

fn get_lib_prefix(kind: &str) -> &str {
match kind {
"lib" | "rlib" => "lib",
"staticlib" | "dylib" | "proc-macro" => {
if cfg!(windows) {
""
} else {
"lib"
}
}
_ => unreachable!()
}
}

fn get_lib_extension(kind: &str) -> &str {
match kind {
"lib" | "rlib" => "rlib",
"staticlib" => {
if cfg!(windows) {
"lib"
} else {
"a"
}
}
"dylib" | "proc-macro" => {
if cfg!(windows) {
"dll"
} else if cfg!(target_os="macos") {
"dylib"
} else {
"so"
}
}
_ => unreachable!()
}
}

fn rm_root(&self) {
self.root.rm_rf()
}
Expand Down