) -> CargoResult<HashMap<Unit<'a>, Vec<Unit<'a>>>> {
let mut deps = HashMap::new();
for unit in roots.iter() {
- // Dependencies of tests should not have `panic` set.
- let profile_for = if unit.mode.is_any_test() {
+ // Dependencies of tests/benches should not have `panic` set.
+ // We check the global test mode to see if we are running in `cargo
+ // test` in which case we ensure all dependencies have `panic`
+ // cleared, and avoid building the lib thrice (once with `panic`, once
+ // without, once for --test). In particular, the lib included for
+ // doctests and examples are `Build` mode here.
+ let profile_for = if unit.mode.is_any_test() || cx.build_config.test {
ProfileFor::TestDependency
} else {
ProfileFor::Any
let tmp = Unit {
pkg: unit.pkg,
target: not_custom_build,
- // The profile here isn't critical. We are just using this temp unit
- // for fetching dependencies that might have `links`.
profile: unit.profile,
kind: unit.kind,
mode: CompileMode::Build,
};
- let deps = deps_of(&tmp, cx, deps, ProfileFor::CustomBuild)?;
+ // TODO: ProfileFor may need to be TestDependency if the random target we
+ // picked is a test and `panic` is set. Need it investigate.
+ let deps = deps_of(&tmp, cx, deps, ProfileFor::Any)?;
Ok(deps.iter()
.filter_map(|unit| {
if !unit.target.linkable() || unit.pkg.manifest().links().is_none() {
// rustdoc only needs rmeta files for regular dependencies.
// However, for plugins/proc-macros, deps should be built like normal.
let mode = check_or_build_mode(&unit.mode, lib);
- let unit = new_unit(
+ let lib_unit = new_unit(
cx,
dep,
lib,
unit.kind.for_target(lib),
mode,
);
- ret.push((unit, ProfileFor::Any));
+ ret.push((lib_unit, ProfileFor::Any));
if let CompileMode::Doc { deps: true } = unit.mode {
- let unit = new_unit(
+ // Document this lib as well.
+ let doc_unit = new_unit(
cx,
dep,
lib,
unit.kind.for_target(lib),
unit.mode,
);
- ret.push((unit, ProfileFor::Any));
+ ret.push((doc_unit, ProfileFor::Any));
}
}
.into_path_unlocked();
let mut build_config = BuildConfig::new(config, jobs, &target, Some(rustc_info_cache))?;
build_config.release = release;
+ build_config.test = mode == CompileMode::Test;
build_config.json_messages = message_format == MessageFormat::Json;
let default_arch_kind = if build_config.requested_target.is_some() {
Kind::Target
// Helper for creating a Unit struct.
let new_unit =
- |pkg: &'a Package, target: &'a Target, mode: CompileMode, profile_for: ProfileFor| {
- let mode = match mode {
+ |pkg: &'a Package, target: &'a Target, target_mode: CompileMode| {
+ let profile_for = if mode == CompileMode::Test {
+ // NOTE: The ProfileFor here is subtle. If you have a profile
+ // with `panic` set, the `panic` flag is cleared for tests and
+ // their dependencies. If we left this as an "Any" profile,
+ // then the lib would get compiled three times (once with
+ // panic, once without, and once with --test).
+ //
+ // This would cause a problem for Doc tests, which would fail
+ // because `rustdoc` would attempt to link with both libraries
+ // at the same time. Also, it's probably not important (or
+ // even desirable?) for rustdoc to link with a lib with
+ // `panic` set.
+ //
+ // As a consequence, Examples and Binaries get compiled
+ // without `panic` set. This probably isn't a bad deal.
+ //
+ // Forcing the lib to be compiled three times during `cargo
+ // test` is probably also not desirable.
+ ProfileFor::TestDependency
+ } else {
+ ProfileFor::Any
+ };
+ let target_mode = match target_mode {
CompileMode::Test => {
if target.is_example() {
// Examples are included as regular binaries to verify
// that they compile.
- // TODO: Broken - Dependencies of examples can be
- // built with `panic`, which will cause `rustdoc` to
- // fail with linking multiple binaries.
CompileMode::Build
} else {
CompileMode::Test
TargetKind::Bench => CompileMode::Bench,
_ => CompileMode::Build,
},
- _ => mode,
+ _ => target_mode,
};
+ // Plugins or proc-macro should be built for the host.
let kind = if target.for_host() {
Kind::Host
} else {
default_arch_kind
};
let profile =
- profiles.get_profile(&pkg.name(), ws.is_member(pkg), profile_for, mode, release);
+ profiles.get_profile(&pkg.name(), ws.is_member(pkg), profile_for, target_mode, release);
Unit {
pkg,
target,
profile,
kind,
- mode,
+ mode: target_mode,
}
};
.iter()
.map(|t| {
(
- new_unit(pkg, t, mode, ProfileFor::Any),
+ new_unit(pkg, t, mode),
!required_features_filterable,
)
})
proposals.extend(default_units);
if mode == CompileMode::Test {
// Include the lib as it will be required for doctests.
- // TODO: Broken - Dependencies won't have ProfileFor::TestDependency.
if let Some(t) = pkg.targets().iter().find(|t| t.is_lib() && t.doctested()) {
- proposals
- .push((new_unit(pkg, t, CompileMode::Build, ProfileFor::Any), false));
+ proposals.push((
+ new_unit(pkg, t, CompileMode::Build),
+ false,
+ ));
}
}
}
} => {
if lib {
if let Some(target) = pkg.targets().iter().find(|t| t.is_lib()) {
- proposals.push((new_unit(pkg, target, mode, ProfileFor::Any), false));
+ proposals.push((new_unit(pkg, target, mode), false));
} else if !all_targets {
bail!("no library targets found")
}
proposals.extend(
list_rule_targets(pkg, bins, "bin", Target::is_bin)?
.into_iter()
- .map(|(t, required)| (new_unit(pkg, t, mode, ProfileFor::Any), required))
+ .map(|(t, required)| (new_unit(pkg, t, mode), required))
.chain(
list_rule_targets(pkg, examples, "example", Target::is_example)?
.into_iter()
.map(|(t, required)| {
- (new_unit(pkg, t, mode, ProfileFor::Any), required)
+ (new_unit(pkg, t, mode), required)
}),
)
.chain(
list_rule_targets(pkg, tests, "test", test_filter)?
.into_iter()
.map(|(t, required)| {
- (new_unit(pkg, t, test_mode, ProfileFor::Any), required)
+ (new_unit(pkg, t, test_mode), required)
}),
)
.chain(
list_rule_targets(pkg, benches, "bench", bench_filter)?
.into_iter()
.map(|(t, required)| {
- (new_unit(pkg, t, bench_mode, ProfileFor::Any), required)
+ (new_unit(pkg, t, bench_mode), required)
}),
)
.collect::<Vec<_>>(),
}
}
- // If any integration tests/benches are being tested, make sure that
+ // If any integration tests/benches are being run, make sure that
// binaries are built as well.
if !mode.is_check() && proposals.iter().any(|&(ref unit, _)| {
unit.mode.is_any_test() && (unit.target.is_test() || unit.target.is_bench())
pkg.targets()
.iter()
.filter(|t| t.is_bin())
- .map(|t| (new_unit(pkg, t, CompileMode::Build, ProfileFor::Any), false)),
+ .map(|t| (new_unit(pkg, t, CompileMode::Build), false)),
);
}