diff --git a/src/cargo/ops/cargo_rustc/compilation.rs b/src/cargo/ops/cargo_rustc/compilation.rs index 758da67db32..9e15288e434 100644 --- a/src/cargo/ops/cargo_rustc/compilation.rs +++ b/src/cargo/ops/cargo_rustc/compilation.rs @@ -42,7 +42,7 @@ pub struct Compilation<'cfg> { pub to_doc_test: Vec, /// Features enabled during this compilation. - pub features: HashSet, + pub cfgs: HashSet, config: &'cfg Config, } @@ -58,7 +58,7 @@ impl<'cfg> Compilation<'cfg> { binaries: Vec::new(), extra_env: HashMap::new(), to_doc_test: Vec::new(), - features: HashSet::new(), + cfgs: HashSet::new(), config: config, } } diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index 91892918756..8461f483783 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -148,11 +148,17 @@ pub fn compile_targets<'a, 'cfg: 'a>(pkg_targets: &'a PackagesToBuild<'a>, } } - if let Some(feats) = cx.resolve.features(root.package_id()) { - cx.compilation.features.extend(feats.iter().cloned()); + let root_pkg = root.package_id(); + if let Some(feats) = cx.resolve.features(root_pkg) { + cx.compilation.cfgs.extend(feats.iter().map(|feat| { + format!("feature=\"{}\"", feat) + })); } for (&(ref pkg, _), output) in cx.build_state.outputs.lock().unwrap().iter() { + if pkg == root_pkg { + cx.compilation.cfgs.extend(output.cfgs.iter().cloned()); + } let any_dylib = output.library_links.iter().any(|l| { !l.starts_with("static=") && !l.starts_with("framework=") }); @@ -392,11 +398,17 @@ fn rustdoc(cx: &mut Context, unit: &Unit) -> CargoResult { } let name = unit.pkg.name().to_string(); - let desc = rustdoc.to_string(); + let build_state = cx.build_state.clone(); + let key = (unit.pkg.package_id().clone(), unit.kind); let exec_engine = cx.exec_engine.clone(); Ok(Work::new(move |desc_tx| { - desc_tx.send(desc).unwrap(); + if let Some(output) = build_state.outputs.lock().unwrap().get(&key) { + for cfg in output.cfgs.iter() { + rustdoc.arg("--cfg").arg(cfg); + } + } + desc_tx.send(rustdoc.to_string()).unwrap(); exec_engine.exec(rustdoc).chain_error(|| { human(format!("Could not document `{}`.", name)) }) diff --git a/src/cargo/ops/cargo_test.rs b/src/cargo/ops/cargo_test.rs index ff2b6b41739..e443748314a 100644 --- a/src/cargo/ops/cargo_test.rs +++ b/src/cargo/ops/cargo_test.rs @@ -136,8 +136,8 @@ fn run_doc_tests(options: &TestOptions, p.arg("--test-args").arg(&test_args.connect(" ")); } - for feat in compilation.features.iter() { - p.arg("--cfg").arg(&format!("feature=\"{}\"", feat)); + for cfg in compilation.cfgs.iter() { + p.arg("--cfg").arg(cfg); } for (_, libs) in compilation.libraries.iter() { diff --git a/tests/test_cargo_compile_custom_build.rs b/tests/test_cargo_compile_custom_build.rs index a28bd463301..b37dd1ae0c2 100644 --- a/tests/test_cargo_compile_custom_build.rs +++ b/tests/test_cargo_compile_custom_build.rs @@ -4,7 +4,7 @@ use std::io::prelude::*; use support::{project, execs}; use support::{COMPILING, RUNNING, DOCTEST, FRESH}; use support::paths::CargoPathExt; -use hamcrest::{assert_that}; +use hamcrest::{assert_that, existing_file, existing_dir}; fn setup() { } @@ -1281,6 +1281,237 @@ test!(cfg_override { execs().with_status(0)); }); +test!(cfg_test { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + build = "build.rs" + "#) + .file("build.rs", r#" + fn main() { + println!("cargo:rustc-cfg=foo"); + } + "#) + .file("src/lib.rs", r#" + /// + /// ``` + /// extern crate foo; + /// + /// fn main() { + /// foo::foo() + /// } + /// ``` + /// + #[cfg(foo)] + pub fn foo() {} + + #[cfg(foo)] + #[test] + fn test_foo() { + foo() + } + "#) + .file("tests/test.rs", r#" + #[cfg(foo)] + #[test] + fn test_bar() {} + "#); + assert_that(p.cargo_process("test").arg("-v"), + execs().with_stdout(format!("\ +{compiling} foo v0.0.1 ({dir}) +{running} [..] build.rs [..] +{running} [..]build-script-build[..] +{running} [..] src[..]lib.rs [..] --cfg foo[..] +{running} [..] src[..]lib.rs [..] --cfg foo[..] +{running} [..] tests[..]test.rs [..] --cfg foo[..] +{running} [..]foo-[..] + +running 1 test +test test_foo ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + +{running} [..]test-[..] + +running 1 test +test test_bar ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + +{doctest} foo +{running} [..] --cfg foo[..] + +running 1 test +test foo_0 ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + +", +compiling = COMPILING, dir = p.url(), running = RUNNING, doctest = DOCTEST))); +}); + +test!(cfg_doc { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + build = "build.rs" + + [dependencies.bar] + path = "bar" + "#) + .file("build.rs", r#" + fn main() { + println!("cargo:rustc-cfg=foo"); + } + "#) + .file("src/lib.rs", r#" + #[cfg(foo)] + pub fn foo() {} + "#) + .file("bar/Cargo.toml", r#" + [package] + name = "bar" + version = "0.0.1" + authors = [] + build = "build.rs" + "#) + .file("bar/build.rs", r#" + fn main() { + println!("cargo:rustc-cfg=bar"); + } + "#) + .file("bar/src/lib.rs", r#" + #[cfg(bar)] + pub fn bar() {} + "#); + assert_that(p.cargo_process("doc"), + execs().with_status(0)); + assert_that(&p.root().join("target/doc"), existing_dir()); + assert_that(&p.root().join("target/doc/foo/fn.foo.html"), existing_file()); + assert_that(&p.root().join("target/doc/bar/fn.bar.html"), existing_file()); +}); + +test!(cfg_override_test { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + build = "build.rs" + links = "a" + "#) + .file("build.rs", "") + .file(".cargo/config", &format!(r#" + [target.{}.a] + rustc-cfg = ["foo"] + "#, ::rustc_host())) + .file("src/lib.rs", r#" + /// + /// ``` + /// extern crate foo; + /// + /// fn main() { + /// foo::foo() + /// } + /// ``` + /// + #[cfg(foo)] + pub fn foo() {} + + #[cfg(foo)] + #[test] + fn test_foo() { + foo() + } + "#) + .file("tests/test.rs", r#" + #[cfg(foo)] + #[test] + fn test_bar() {} + "#); + assert_that(p.cargo_process("test").arg("-v"), + execs().with_stdout(format!("\ +{compiling} foo v0.0.1 ({dir}) +{running} [..] src[..]lib.rs [..] --cfg foo[..] +{running} [..] src[..]lib.rs [..] --cfg foo[..] +{running} [..] tests[..]test.rs [..] --cfg foo[..] +{running} [..]foo-[..] + +running 1 test +test test_foo ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + +{running} [..]test-[..] + +running 1 test +test test_bar ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + +{doctest} foo +{running} [..] --cfg foo[..] + +running 1 test +test foo_0 ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + +", +compiling = COMPILING, dir = p.url(), running = RUNNING, doctest = DOCTEST))); +}); + +test!(cfg_override_doc { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + build = "build.rs" + links = "a" + + [dependencies.bar] + path = "bar" + "#) + .file(".cargo/config", &format!(r#" + [target.{target}.a] + rustc-cfg = ["foo"] + [target.{target}.b] + rustc-cfg = ["bar"] + "#, target = ::rustc_host())) + .file("build.rs", "") + .file("src/lib.rs", r#" + #[cfg(foo)] + pub fn foo() {} + "#) + .file("bar/Cargo.toml", r#" + [package] + name = "bar" + version = "0.0.1" + authors = [] + build = "build.rs" + links = "b" + "#) + .file("bar/build.rs", "") + .file("bar/src/lib.rs", r#" + #[cfg(bar)] + pub fn bar() {} + "#) ; + assert_that(p.cargo_process("doc"), + execs().with_status(0)); + assert_that(&p.root().join("target/doc"), existing_dir()); + assert_that(&p.root().join("target/doc/foo/fn.foo.html"), existing_file()); + assert_that(&p.root().join("target/doc/bar/fn.bar.html"), existing_file()); +}); + test!(flags_go_into_tests { let p = project("foo") .file("Cargo.toml", r#" diff --git a/tests/test_cargo_doc.rs b/tests/test_cargo_doc.rs index 93517837978..232be534c2d 100644 --- a/tests/test_cargo_doc.rs +++ b/tests/test_cargo_doc.rs @@ -477,3 +477,46 @@ test!(doc_multiple_deps { assert_that(&p.root().join("target/doc/bar/index.html"), existing_file()); assert_that(&p.root().join("target/doc/baz/index.html"), existing_file()); }); + +test!(features { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [dependencies.bar] + path = "bar" + + [features] + foo = ["bar/bar"] + "#) + .file("src/lib.rs", r#" + #[cfg(feature = "foo")] + pub fn foo() {} + "#) + .file("bar/Cargo.toml", r#" + [package] + name = "bar" + version = "0.0.1" + authors = [] + + [features] + bar = [] + "#) + .file("bar/build.rs", r#" + fn main() { + println!("cargo:rustc-cfg=bar"); + } + "#) + .file("bar/src/lib.rs", r#" + #[cfg(feature = "bar")] + pub fn bar() {} + "#); + assert_that(p.cargo_process("doc").arg("--features").arg("foo"), + execs().with_status(0)); + assert_that(&p.root().join("target/doc"), existing_dir()); + assert_that(&p.root().join("target/doc/foo/fn.foo.html"), existing_file()); + assert_that(&p.root().join("target/doc/bar/fn.bar.html"), existing_file()); +});