| //! Tests specific to artifact dependencies, designated using |
| //! the new `dep = { artifact = "bin", … }` syntax in manifests. |
| |
| use cargo_test_support::compare::assert_e2e; |
| use cargo_test_support::prelude::*; |
| use cargo_test_support::registry::{Package, RegistryBuilder}; |
| use cargo_test_support::str; |
| use cargo_test_support::{ |
| basic_bin_manifest, basic_manifest, cross_compile, project, publish, registry, rustc_host, |
| Project, |
| }; |
| |
| #[cargo_test] |
| fn check_with_invalid_artifact_dependency() { |
| // invalid name |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [dependencies] |
| bar = { path = "bar/", artifact = "unknown" } |
| "#, |
| ) |
| .file("src/lib.rs", "extern crate bar;") // this would fail but we don't get there, artifacts are no libs |
| .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) |
| .file("bar/src/lib.rs", "") |
| .build(); |
| p.cargo("check -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` |
| |
| Caused by: |
| 'unknown' is not a valid artifact specifier |
| |
| "#]]) |
| .with_status(101) |
| .run(); |
| |
| fn run_cargo_with_and_without_bindeps_feature( |
| p: &Project, |
| cmd: &str, |
| assert: &dyn Fn(&mut cargo_test_support::Execs), |
| ) { |
| assert( |
| p.cargo(&format!("{} -Z bindeps", cmd)) |
| .masquerade_as_nightly_cargo(&["bindeps"]), |
| ); |
| assert(&mut p.cargo(cmd)); |
| } |
| |
| // lib specified without artifact |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| |
| [dependencies] |
| bar = { path = "bar/", lib = true } |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) |
| .file("bar/src/lib.rs", "") |
| .build(); |
| run_cargo_with_and_without_bindeps_feature(&p, "check", &|cargo| { |
| cargo |
| .with_stderr_data(str![[r#" |
| [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` |
| |
| Caused by: |
| 'lib' specifier cannot be used without an 'artifact = …' value (bar) |
| |
| "#]]) |
| .with_status(101) |
| .run(); |
| }); |
| |
| // target specified without artifact |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| |
| [dependencies] |
| bar = { path = "bar/", target = "target" } |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) |
| .file("bar/src/lib.rs", "") |
| .build(); |
| run_cargo_with_and_without_bindeps_feature(&p, "check", &|cargo| { |
| cargo |
| .with_stderr_data(str![[r#" |
| [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` |
| |
| Caused by: |
| 'target' specifier cannot be used without an 'artifact = …' value (bar) |
| |
| "#]]) |
| .with_status(101) |
| .run(); |
| }) |
| } |
| |
| #[cargo_test] |
| fn check_with_invalid_target_triple() { |
| // invalid name |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [dependencies] |
| bar = { path = "bar/", artifact = "bin", target = "unknown-target-triple" } |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) |
| .file("bar/src/main.rs", "fn main() {}") |
| .build(); |
| p.cargo("check -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [ERROR] failed to run `rustc` to learn about target-specific information |
| |
| Caused by: |
| process didn't exit successfully: `rustc - --crate-name ___ --print=file-names --target unknown-target-triple [..]` ([EXIT_STATUS]: 1) |
| --- stderr |
| ... |
| |
| |
| "#]]) |
| .with_status(101) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn build_without_nightly_aborts_with_error() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [dependencies] |
| bar = { path = "bar/", artifact = "bin" } |
| "#, |
| ) |
| .file("src/lib.rs", "extern crate bar;") |
| .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) |
| .file("bar/src/lib.rs", "") |
| .build(); |
| p.cargo("check") |
| .with_status(101) |
| .with_stderr_data(str![[r#" |
| [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` |
| |
| Caused by: |
| `artifact = …` requires `-Z bindeps` (bar) |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn disallow_artifact_and_no_artifact_dep_to_same_package_within_the_same_dep_category() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [dependencies] |
| bar = { path = "bar/", artifact = "bin" } |
| bar_stable = { path = "bar/", package = "bar" } |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .file("bar/Cargo.toml", &basic_bin_manifest("bar")) |
| .file("bar/src/main.rs", "fn main() {}") |
| .build(); |
| p.cargo("check -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_status(101) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [WARNING] foo v0.0.0 ([ROOT]/foo) ignoring invalid dependency `bar_stable` which is missing a lib target |
| [ERROR] the crate `foo v0.0.0 ([ROOT]/foo)` depends on crate `bar v0.5.0 ([ROOT]/foo/bar)` multiple times with different names |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn features_are_unified_among_lib_and_bin_dep_of_same_target() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.1" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [dependencies.d1] |
| path = "d1" |
| features = ["d1f1"] |
| artifact = "bin" |
| lib = true |
| |
| [dependencies.d2] |
| path = "d2" |
| features = ["d2f2"] |
| "#, |
| ) |
| .file( |
| "src/main.rs", |
| r#" |
| fn main() { |
| d1::f1(); |
| d1::f2(); |
| d2::f1(); |
| d2::f2(); |
| } |
| "#, |
| ) |
| .file( |
| "d1/Cargo.toml", |
| r#" |
| [package] |
| name = "d1" |
| version = "0.0.1" |
| edition = "2015" |
| authors = [] |
| |
| [features] |
| d1f1 = ["d2"] |
| |
| [dependencies.d2] |
| path = "../d2" |
| features = ["d2f1"] |
| optional = true |
| "#, |
| ) |
| .file( |
| "d1/src/main.rs", |
| r#"fn main() { |
| #[cfg(feature = "d1f1")] |
| d2::f1(); |
| |
| // Using f2 is only possible as features are unififed across the same target. |
| // Our own manifest would only enable f1, and f2 comes in because a parent crate |
| // enables the feature in its manifest. |
| #[cfg(feature = "d1f1")] |
| d2::f2(); |
| }"#, |
| ) |
| .file( |
| "d1/src/lib.rs", |
| r#" |
| #[cfg(feature = "d2")] |
| extern crate d2; |
| /// Importing f2 here shouldn't be possible as unless features are unified. |
| #[cfg(feature = "d1f1")] |
| pub use d2::{f1, f2}; |
| "#, |
| ) |
| .file( |
| "d2/Cargo.toml", |
| r#" |
| [package] |
| name = "d2" |
| version = "0.0.1" |
| edition = "2015" |
| authors = [] |
| |
| [features] |
| d2f1 = [] |
| d2f2 = [] |
| "#, |
| ) |
| .file( |
| "d2/src/lib.rs", |
| r#" |
| #[cfg(feature = "d2f1")] pub fn f1() {} |
| #[cfg(feature = "d2f2")] pub fn f2() {} |
| "#, |
| ) |
| .build(); |
| |
| p.cargo("build -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 2 packages to latest compatible versions |
| [COMPILING] d2 v0.0.1 ([ROOT]/foo/d2) |
| [COMPILING] d1 v0.0.1 ([ROOT]/foo/d1) |
| [COMPILING] foo v0.0.1 ([ROOT]/foo) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn features_are_not_unified_among_lib_and_bin_dep_of_different_target() { |
| if cross_compile::disabled() { |
| return; |
| } |
| let target = cross_compile::alternate(); |
| let p = project() |
| .file( |
| "Cargo.toml", |
| &r#" |
| [package] |
| name = "foo" |
| version = "0.0.1" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [dependencies.d1] |
| path = "d1" |
| features = ["d1f1"] |
| artifact = "bin" |
| lib = true |
| target = "$TARGET" |
| |
| [dependencies.d2] |
| path = "d2" |
| features = ["d2f2"] |
| "# |
| .replace("$TARGET", target), |
| ) |
| .file( |
| "src/main.rs", |
| r#" |
| fn main() { |
| // the lib = true part always builds for our current target, unifying dependencies |
| d1::d2::f1(); |
| d1::d2::f2(); |
| d2::f1(); |
| d2::f2(); |
| } |
| "#, |
| ) |
| .file( |
| "d1/Cargo.toml", |
| r#" |
| [package] |
| name = "d1" |
| version = "0.0.1" |
| edition = "2015" |
| authors = [] |
| |
| [features] |
| d1f1 = ["d2"] |
| |
| [dependencies.d2] |
| path = "../d2" |
| features = ["d2f1"] |
| optional = true |
| "#, |
| ) |
| .file("d1/src/main.rs", r#"fn main() { |
| // f1 we set ourselves |
| d2::f1(); |
| // As 'main' is only compiled as part of the artifact dependency and since that is not unified |
| // if the target differs, trying to access f2 is a compile time error as the feature isn't enabled in our dependency tree. |
| d2::f2(); |
| }"#) |
| .file( |
| "d1/src/lib.rs", |
| r#" |
| #[cfg(feature = "d2")] |
| pub extern crate d2; |
| "#, |
| ) |
| .file( |
| "d2/Cargo.toml", |
| r#" |
| [package] |
| name = "d2" |
| version = "0.0.1" |
| edition = "2015" |
| authors = [] |
| |
| [features] |
| d2f1 = [] |
| d2f2 = [] |
| "#, |
| ) |
| .file( |
| "d2/src/lib.rs", |
| r#" |
| #[cfg(feature = "d2f1")] pub fn f1() {} |
| #[cfg(feature = "d2f2")] pub fn f2() {} |
| "#, |
| ) |
| .build(); |
| |
| p.cargo("build -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_status(101) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 2 packages to latest compatible versions |
| [COMPILING] d2 v0.0.1 ([ROOT]/foo/d2) |
| [COMPILING] d1 v0.0.1 ([ROOT]/foo/d1) |
| error[E0425]: cannot find function `f2` in crate `d2` |
| ... |
| |
| For more information about this error, try `rustc --explain E0425`. |
| [ERROR] could not compile `d1` (bin "d1") due to 1 previous error |
| ... |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn feature_resolution_works_for_cfg_target_specification() { |
| if cross_compile::disabled() { |
| return; |
| } |
| let target = cross_compile::alternate(); |
| let p = project() |
| .file( |
| "Cargo.toml", |
| &r#" |
| [package] |
| name = "foo" |
| version = "0.0.1" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [dependencies.d1] |
| path = "d1" |
| artifact = "bin" |
| target = "$TARGET" |
| "# |
| .replace("$TARGET", target), |
| ) |
| .file( |
| "src/main.rs", |
| r#" |
| fn main() { |
| let _b = include_bytes!(env!("CARGO_BIN_FILE_D1")); |
| } |
| "#, |
| ) |
| .file( |
| "d1/Cargo.toml", |
| &r#" |
| [package] |
| name = "d1" |
| version = "0.0.1" |
| edition = "2015" |
| authors = [] |
| |
| [target.'$TARGET'.dependencies] |
| d2 = { path = "../d2" } |
| "# |
| .replace("$TARGET", target), |
| ) |
| .file( |
| "d1/src/main.rs", |
| r#"fn main() { |
| d1::f(); |
| }"#, |
| ) |
| .file("d1/build.rs", r#"fn main() { }"#) |
| .file( |
| "d1/src/lib.rs", |
| &r#"pub fn f() { |
| #[cfg(target = "$TARGET")] |
| d2::f(); |
| } |
| "# |
| .replace("$TARGET", target), |
| ) |
| .file( |
| "d2/Cargo.toml", |
| r#" |
| [package] |
| name = "d2" |
| version = "0.0.1" |
| edition = "2015" |
| authors = [] |
| "#, |
| ) |
| .file("d2/build.rs", r#"fn main() { }"#) |
| .file("d2/src/lib.rs", "pub fn f() {}") |
| .build(); |
| |
| p.cargo("test -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn build_script_with_bin_artifacts() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [build-dependencies] |
| bar = { path = "bar/", artifact = ["bin", "staticlib", "cdylib"] } |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .file("build.rs", r#" |
| fn main() { |
| let baz: std::path::PathBuf = std::env::var("CARGO_BIN_FILE_BAR_baz").expect("CARGO_BIN_FILE_BAR_baz").into(); |
| println!("{}", baz.display()); |
| assert!(&baz.is_file()); |
| |
| let lib: std::path::PathBuf = std::env::var("CARGO_STATICLIB_FILE_BAR_bar").expect("CARGO_STATICLIB_FILE_BAR_bar").into(); |
| println!("{}", lib.display()); |
| assert!(&lib.is_file()); |
| |
| let lib: std::path::PathBuf = std::env::var("CARGO_CDYLIB_FILE_BAR_bar").expect("CARGO_CDYLIB_FILE_BAR_bar").into(); |
| println!("{}", lib.display()); |
| assert!(&lib.is_file()); |
| |
| let dir: std::path::PathBuf = std::env::var("CARGO_BIN_DIR_BAR").expect("CARGO_BIN_DIR_BAR").into(); |
| println!("{}", dir.display()); |
| assert!(dir.is_dir()); |
| |
| let bar: std::path::PathBuf = std::env::var("CARGO_BIN_FILE_BAR").expect("CARGO_BIN_FILE_BAR").into(); |
| println!("{}", bar.display()); |
| assert!(&bar.is_file()); |
| |
| let bar2: std::path::PathBuf = std::env::var("CARGO_BIN_FILE_BAR_bar").expect("CARGO_BIN_FILE_BAR_bar").into(); |
| println!("{}", bar2.display()); |
| assert_eq!(bar, bar2); |
| } |
| "#) |
| .file( |
| "bar/Cargo.toml", |
| r#" |
| [package] |
| name = "bar" |
| version = "0.5.0" |
| edition = "2015" |
| authors = [] |
| |
| [lib] |
| crate-type = ["staticlib", "cdylib"] |
| "#, |
| ) |
| // compilation target is native for build scripts unless overridden |
| .file("bar/src/bin/bar.rs", &format!(r#"fn main() {{ assert_eq!(std::env::var("TARGET").unwrap(), "{}"); }}"#, cross_compile::native())) |
| .file("bar/src/bin/baz.rs", "fn main() {}") |
| .file("bar/src/lib.rs", "") |
| .build(); |
| p.cargo("build -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data( |
| str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [COMPILING] foo v0.0.0 ([ROOT]/foo) |
| [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]] |
| .unordered(), |
| ) |
| .run(); |
| |
| let build_script_output = build_script_output_string(&p, "foo"); |
| // we need the binary directory for this artifact along with all binary paths |
| if cfg!(target_env = "msvc") { |
| assert_e2e().eq( |
| &build_script_output, |
| str![[r#" |
| [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/bin/baz[EXE] |
| [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/staticlib/bar-[HASH].lib |
| [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/cdylib/bar.dll |
| [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/bin |
| [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/bin/bar[EXE] |
| [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/bin/bar[EXE] |
| |
| "#]], |
| ); |
| } else { |
| assert_e2e().eq( |
| &build_script_output, |
| str![[r#" |
| [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/bin/baz-[HASH][EXE] |
| [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/staticlib/libbar-[HASH].a |
| [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/cdylib/[..]bar.[..] |
| [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/bin |
| [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/bin/bar-[HASH][EXE] |
| [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/bin/bar-[HASH][EXE] |
| |
| "#]], |
| ); |
| } |
| |
| assert!( |
| !p.bin("bar").is_file(), |
| "artifacts are located in their own directory, exclusively, and won't be lifted up" |
| ); |
| assert!(!p.bin("baz").is_file(),); |
| assert_artifact_executable_output(&p, "debug", "bar", "bar"); |
| } |
| |
| #[cargo_test] |
| fn build_script_with_bin_artifact_and_lib_false() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [build-dependencies] |
| bar = { path = "bar/", artifact = "bin" } |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .file( |
| "build.rs", |
| r#" |
| fn main() { |
| bar::doit() |
| } |
| "#, |
| ) |
| .file("bar/Cargo.toml", &basic_bin_manifest("bar")) |
| .file("bar/src/main.rs", "fn main() { bar::doit(); }") |
| .file( |
| "bar/src/lib.rs", |
| r#" |
| pub fn doit() { |
| panic!("sentinel"); |
| } |
| "#, |
| ) |
| .build(); |
| |
| #[expect(deprecated)] |
| p.cargo("build -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_status(101) |
| .with_stderr_does_not_contain("[..]sentinel[..]") |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn lib_with_bin_artifact_and_lib_false() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [dependencies] |
| bar = { path = "bar/", artifact = "bin" } |
| "#, |
| ) |
| .file( |
| "src/lib.rs", |
| r#" |
| pub fn foo() { |
| bar::doit() |
| }"#, |
| ) |
| .file("bar/Cargo.toml", &basic_bin_manifest("bar")) |
| .file("bar/src/main.rs", "fn main() { bar::doit(); }") |
| .file( |
| "bar/src/lib.rs", |
| r#" |
| pub fn doit() { |
| panic!("sentinel"); |
| } |
| "#, |
| ) |
| .build(); |
| |
| #[expect(deprecated)] |
| p.cargo("build -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_status(101) |
| .with_stderr_does_not_contain("[..]sentinel[..]") |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn build_script_with_selected_dashed_bin_artifact_and_lib_true() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [build-dependencies] |
| bar-baz = { path = "bar/", artifact = "bin:baz-suffix", lib = true } |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .file("build.rs", r#" |
| fn main() { |
| bar_baz::print_env() |
| } |
| "#) |
| .file( |
| "bar/Cargo.toml", |
| r#" |
| [package] |
| name = "bar-baz" |
| version = "0.5.0" |
| edition = "2015" |
| authors = [] |
| |
| [[bin]] |
| name = "bar" |
| |
| [[bin]] |
| name = "baz-suffix" |
| "#, |
| ) |
| .file("bar/src/main.rs", "fn main() {}") |
| .file("bar/src/lib.rs", r#" |
| pub fn print_env() { |
| let dir: std::path::PathBuf = std::env::var("CARGO_BIN_DIR_BAR_BAZ").expect("CARGO_BIN_DIR_BAR_BAZ").into(); |
| let bin: std::path::PathBuf = std::env::var("CARGO_BIN_FILE_BAR_BAZ_baz-suffix").expect("CARGO_BIN_FILE_BAR_BAZ_baz-suffix").into(); |
| println!("{}", dir.display()); |
| println!("{}", bin.display()); |
| assert!(dir.is_dir()); |
| assert!(&bin.is_file()); |
| assert!(std::env::var("CARGO_BIN_FILE_BAR_BAZ").is_err(), "CARGO_BIN_FILE_BAR_BAZ isn't set due to name mismatch"); |
| assert!(std::env::var("CARGO_BIN_FILE_BAR_BAZ_bar").is_err(), "CARGO_BIN_FILE_BAR_BAZ_bar isn't set as binary isn't selected"); |
| } |
| "#) |
| .build(); |
| p.cargo("build -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [COMPILING] bar-baz v0.5.0 ([ROOT]/foo/bar) |
| [COMPILING] foo v0.0.0 ([ROOT]/foo) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| |
| let build_script_output = build_script_output_string(&p, "foo"); |
| // we need the binary directory for this artifact and the binary itself |
| if cfg!(target_env = "msvc") { |
| assert_e2e().eq( |
| &build_script_output, |
| str![[r#" |
| [ROOT]/foo/target/debug/deps/artifact/bar-baz-[HASH]/bin |
| [ROOT]/foo/target/debug/deps/artifact/bar-baz-[HASH]/bin/baz_suffix[EXE] |
| |
| "#]], |
| ); |
| } else { |
| assert_e2e().eq( |
| &build_script_output, |
| str![[r#" |
| [ROOT]/foo/target/debug/deps/artifact/bar-baz-[HASH]/bin |
| [ROOT]/foo/target/debug/deps/artifact/bar-baz-[HASH]/bin/baz_suffix-[HASH][EXE] |
| |
| "#]], |
| ); |
| } |
| |
| assert!( |
| !p.bin("bar").is_file(), |
| "artifacts are located in their own directory, exclusively, and won't be lifted up" |
| ); |
| assert_artifact_executable_output(&p, "debug", "bar", "baz_suffix"); |
| } |
| |
| #[cargo_test] |
| fn lib_with_selected_dashed_bin_artifact_and_lib_true() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [dependencies] |
| bar-baz = { path = "bar/", artifact = ["bin:baz-suffix", "staticlib", "cdylib"], lib = true } |
| "#, |
| ) |
| .file( |
| "src/lib.rs", |
| r#" |
| pub fn foo() { |
| bar_baz::exists(); |
| |
| env!("CARGO_BIN_DIR_BAR_BAZ"); |
| let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR_BAZ_baz-suffix")); |
| let _b = include_bytes!(env!("CARGO_STATICLIB_FILE_BAR_BAZ")); |
| let _b = include_bytes!(env!("CARGO_STATICLIB_FILE_BAR_BAZ_bar-baz")); |
| let _b = include_bytes!(env!("CARGO_STATICLIB_FILE_BAR_BAZ_bar_baz")); |
| let _b = include_bytes!(env!("CARGO_CDYLIB_FILE_BAR_BAZ")); |
| let _b = include_bytes!(env!("CARGO_CDYLIB_FILE_BAR_BAZ_bar-baz")); |
| let _b = include_bytes!(env!("CARGO_CDYLIB_FILE_BAR_BAZ_bar_baz")); |
| } |
| "#, |
| ) |
| .file( |
| "bar/Cargo.toml", |
| r#" |
| [package] |
| name = "bar-baz" |
| version = "0.5.0" |
| edition = "2015" |
| authors = [] |
| |
| [lib] |
| crate-type = ["rlib", "staticlib", "cdylib"] |
| |
| [[bin]] |
| name = "bar" |
| |
| [[bin]] |
| name = "baz-suffix" |
| "#, |
| ) |
| .file("bar/src/main.rs", "fn main() {}") |
| .file("bar/src/lib.rs", "pub fn exists() {}") |
| .build(); |
| p.cargo("build -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [COMPILING] bar-baz v0.5.0 ([ROOT]/foo/bar) |
| [COMPILING] foo v0.0.0 ([ROOT]/foo) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| |
| assert!( |
| !p.bin("bar").is_file(), |
| "artifacts are located in their own directory, exclusively, and won't be lifted up" |
| ); |
| assert_artifact_executable_output(&p, "debug", "bar", "baz_suffix"); |
| } |
| |
| #[cargo_test] |
| fn allow_artifact_and_no_artifact_dep_to_same_package_within_different_dep_categories() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [dependencies] |
| bar = { path = "bar/", artifact = "bin" } |
| |
| [dev-dependencies] |
| bar = { path = "bar/", package = "bar" } |
| "#, |
| ) |
| .file( |
| "src/lib.rs", |
| r#" |
| #[cfg(test)] extern crate bar; |
| pub fn foo() { |
| env!("CARGO_BIN_DIR_BAR"); |
| let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); |
| }"#, |
| ) |
| .file("bar/Cargo.toml", &basic_bin_manifest("bar")) |
| .file("bar/src/main.rs", "fn main() {}") |
| .file("bar/src/lib.rs", "") |
| .build(); |
| p.cargo("test -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) |
| [COMPILING] foo v0.0.0 ([ROOT]/foo) |
| [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) |
| [DOCTEST] foo |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn normal_build_deps_are_picked_up_in_presence_of_an_artifact_build_dep_to_the_same_package() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [dependencies] |
| bar = { path = "bar", artifact = "bin:bar" } |
| |
| [build-dependencies] |
| bar = { path = "bar" } |
| "#, |
| ) |
| .file("build.rs", "fn main() { bar::f(); }") |
| .file( |
| "src/lib.rs", |
| r#" |
| pub fn foo() { |
| env!("CARGO_BIN_DIR_BAR"); |
| let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); |
| }"#, |
| ) |
| .file("bar/Cargo.toml", &basic_bin_manifest("bar")) |
| .file("bar/src/main.rs", "fn main() {}") |
| .file("bar/src/lib.rs", "pub fn f() {}") |
| .build(); |
| p.cargo("check -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn disallow_using_example_binaries_as_artifacts() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [dependencies] |
| bar = { path = "bar/", artifact = "bin:one-example" } |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .file("bar/Cargo.toml", &basic_bin_manifest("bar")) |
| .file("bar/src/main.rs", "fn main() {}") |
| .file("bar/examples/one-example.rs", "fn main() {}") |
| .build(); |
| p.cargo("build -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_status(101) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [ERROR] dependency `bar` in package `foo` requires a `bin:one-example` artifact to be present. |
| |
| "#]]) |
| .run(); |
| } |
| |
| /// From RFC 3028 |
| /// |
| /// > You may also specify separate dependencies with different artifact values, as well as |
| /// dependencies on the same crate without artifact specified; for instance, you may have a |
| /// build dependency on the binary of a crate and a normal dependency on the Rust library of the same crate. |
| #[cargo_test] |
| fn allow_artifact_and_non_artifact_dependency_to_same_crate() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [build-dependencies] |
| bar = { path = "bar/", artifact = "bin" } |
| |
| [dependencies] |
| bar = { path = "bar/" } |
| "#, |
| ) |
| .file("src/lib.rs", r#" |
| pub fn foo() { |
| bar::doit(); |
| assert!(option_env!("CARGO_BIN_FILE_BAR").is_none()); |
| }"#) |
| .file( |
| "build.rs", |
| r#" |
| fn main() { |
| assert!(option_env!("CARGO_BIN_FILE_BAR").is_none(), "no environment variables at build time"); |
| std::process::Command::new(std::env::var("CARGO_BIN_FILE_BAR").expect("BAR present")).status().unwrap(); |
| }"#, |
| ) |
| .file("bar/Cargo.toml", &basic_bin_manifest("bar")) |
| .file("bar/src/main.rs", "fn main() {}") |
| .file("bar/src/lib.rs", "pub fn doit() {}") |
| .build(); |
| |
| p.cargo("check -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) |
| [COMPILING] foo v0.0.0 ([ROOT]/foo) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn build_script_deps_adopt_specified_target_unconditionally() { |
| if cross_compile::disabled() { |
| return; |
| } |
| |
| let target = cross_compile::alternate(); |
| let p = project() |
| .file( |
| "Cargo.toml", |
| &format!( |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [build-dependencies.bar] |
| path = "bar/" |
| artifact = "bin" |
| target = "{}" |
| "#, |
| target |
| ), |
| ) |
| .file("src/lib.rs", "") |
| .file("build.rs", r#" |
| fn main() { |
| let bar: std::path::PathBuf = std::env::var("CARGO_BIN_FILE_BAR").expect("CARGO_BIN_FILE_BAR").into(); |
| assert!(&bar.is_file()); |
| }"#) |
| .file("bar/Cargo.toml", &basic_bin_manifest("bar")) |
| .file("bar/src/main.rs", "fn main() {}") |
| .file("bar/src/lib.rs", "pub fn doit() {}") |
| .build(); |
| |
| #[expect(deprecated)] |
| p.cargo("check -v -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_does_not_contain( |
| "[RUNNING] `rustc --crate-name build_script_build --edition=2015 build.rs [..]--target [ALT_TARGET] [..]", |
| ) |
| .with_stderr_contains("[RUNNING] `rustc --crate-name build_script_build --edition=2015 build.rs [..]") |
| .with_stderr_contains( |
| "[RUNNING] `rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--target [ALT_TARGET] [..]", |
| ) |
| .with_stderr_contains( |
| "[RUNNING] `rustc --crate-name bar --edition=2015 bar/src/main.rs [..]--target [ALT_TARGET] [..]", |
| ) |
| .with_stderr_does_not_contain( |
| "[RUNNING] `rustc --crate-name foo [..]--target [ALT_TARGET] [..]", |
| ) |
| .with_stderr_contains("[RUNNING] `rustc --crate-name foo [..]") |
| .run(); |
| } |
| |
| /// inverse RFC-3176 |
| #[cargo_test] |
| fn build_script_deps_adopt_do_not_allow_multiple_targets_under_different_name_and_same_version() { |
| if cross_compile::disabled() { |
| return; |
| } |
| |
| let alternate = cross_compile::alternate(); |
| let native = cross_compile::native(); |
| let p = project() |
| .file( |
| "Cargo.toml", |
| &format!( |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [build-dependencies.bar] |
| path = "bar/" |
| artifact = "bin" |
| target = "{}" |
| |
| [build-dependencies.bar-native] |
| package = "bar" |
| path = "bar/" |
| artifact = "bin" |
| target = "{}" |
| "#, |
| alternate, |
| native |
| ), |
| ) |
| .file("src/lib.rs", "") |
| .file("build.rs", r#" |
| fn main() { |
| let bar: std::path::PathBuf = std::env::var("CARGO_BIN_FILE_BAR").expect("CARGO_BIN_FILE_BAR").into(); |
| assert!(&bar.is_file()); |
| let bar_native: std::path::PathBuf = std::env::var("CARGO_BIN_FILE_BAR_NATIVE_bar").expect("CARGO_BIN_FILE_BAR_NATIVE_bar").into(); |
| assert!(&bar_native.is_file()); |
| assert_ne!(bar_native, bar, "should build different binaries due to different targets"); |
| }"#) |
| .file("bar/Cargo.toml", &basic_bin_manifest("bar")) |
| .file("bar/src/main.rs", "fn main() {}") |
| .build(); |
| |
| p.cargo("check -v -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_status(101) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [ERROR] the crate `foo v0.0.0 ([ROOT]/foo)` depends on crate `bar v0.5.0 ([ROOT]/foo/bar)` multiple times with different names |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn non_build_script_deps_adopt_specified_target_unconditionally() { |
| if cross_compile::disabled() { |
| return; |
| } |
| |
| let target = cross_compile::alternate(); |
| let p = project() |
| .file( |
| "Cargo.toml", |
| &format!( |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [dependencies.bar] |
| path = "bar/" |
| artifact = "bin" |
| target = "{}" |
| "#, |
| target |
| ), |
| ) |
| .file( |
| "src/lib.rs", |
| r#"pub fn foo() { let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); }"#, |
| ) |
| .file("bar/Cargo.toml", &basic_bin_manifest("bar")) |
| .file("bar/src/main.rs", "fn main() {}") |
| .file("bar/src/lib.rs", "pub fn doit() {}") |
| .build(); |
| |
| #[expect(deprecated)] |
| p.cargo("check -v -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_contains( |
| "[RUNNING] `rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--target [ALT_TARGET] [..]", |
| ) |
| .with_stderr_contains( |
| "[RUNNING] `rustc --crate-name bar --edition=2015 bar/src/main.rs [..]--target [ALT_TARGET] [..]", |
| ) |
| .with_stderr_does_not_contain( |
| "[RUNNING] `rustc --crate-name foo [..]--target [ALT_TARGET] [..]", |
| ) |
| .with_stderr_contains("[RUNNING] `rustc --crate-name foo [..]") |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn no_cross_doctests_works_with_artifacts() { |
| if cross_compile::disabled() { |
| return; |
| } |
| |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.1" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [dependencies] |
| bar = { path = "bar/", artifact = "bin", lib = true } |
| "#, |
| ) |
| .file( |
| "src/lib.rs", |
| r#" |
| //! ``` |
| //! env!("CARGO_BIN_DIR_BAR"); |
| //! let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); |
| //! ``` |
| pub fn foo() { |
| env!("CARGO_BIN_DIR_BAR"); |
| let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); |
| } |
| "#, |
| ) |
| .file("bar/Cargo.toml", &basic_bin_manifest("bar")) |
| .file("bar/src/lib.rs", r#"pub extern "C" fn c() {}"#) |
| .file("bar/src/main.rs", "fn main() {}") |
| .build(); |
| |
| let target = rustc_host(); |
| p.cargo("test -Z bindeps --target") |
| .arg(&target) |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) |
| [COMPILING] foo v0.0.1 ([ROOT]/foo) |
| [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| [RUNNING] unittests src/lib.rs (target/[HOST_TARGET]/debug/deps/foo-[HASH][EXE]) |
| [DOCTEST] foo |
| |
| "#]]) |
| .run(); |
| |
| println!("c"); |
| let target = cross_compile::alternate(); |
| |
| // This will build the library, but does not build or run doc tests. |
| // This should probably be a warning or error. |
| p.cargo("test -Z bindeps -v --doc --target") |
| .arg(&target) |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) |
| [RUNNING] `rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--target [ALT_TARGET] [..] |
| [RUNNING] `rustc --crate-name bar --edition=2015 bar/src/main.rs [..]--target [ALT_TARGET] [..] |
| [COMPILING] foo v0.0.1 ([ROOT]/foo) |
| [RUNNING] `rustc --crate-name foo [..]` |
| [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| [NOTE] skipping doctests for foo v0.0.1 ([ROOT]/foo) (lib), cross-compilation doctests are not yet supported |
| See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#doctest-xcompile for more information. |
| |
| "#]]) |
| .run(); |
| |
| if !cross_compile::can_run_on_host() { |
| return; |
| } |
| |
| // This tests the library, but does not run the doc tests. |
| p.cargo("test -Z bindeps -v --target") |
| .arg(&target) |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [FRESH] bar v0.5.0 ([ROOT]/foo/bar) |
| [COMPILING] foo v0.0.1 ([ROOT]/foo) |
| [RUNNING] `rustc --crate-name foo [..]--test[..] |
| [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| [RUNNING] `[ROOT]/foo/target/[ALT_TARGET]/debug/deps/foo-[HASH][EXE]` |
| [NOTE] skipping doctests for foo v0.0.1 ([ROOT]/foo) (lib), cross-compilation doctests are not yet supported |
| See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#doctest-xcompile for more information. |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn build_script_deps_adopts_target_platform_if_target_equals_target() { |
| if cross_compile::disabled() { |
| return; |
| } |
| |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [build-dependencies] |
| bar = { path = "bar/", artifact = "bin", target = "target" } |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .file("build.rs", r#" |
| fn main() { |
| let bar: std::path::PathBuf = std::env::var("CARGO_BIN_FILE_BAR").expect("CARGO_BIN_FILE_BAR").into(); |
| assert!(&bar.is_file()); |
| }"#) |
| .file("bar/Cargo.toml", &basic_bin_manifest("bar")) |
| .file("bar/src/main.rs", "fn main() {}") |
| .file("bar/src/lib.rs", "pub fn doit() {}") |
| .build(); |
| |
| let alternate_target = cross_compile::alternate(); |
| #[expect(deprecated)] |
| p.cargo("check -v -Z bindeps --target") |
| .arg(alternate_target) |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_does_not_contain( |
| "[RUNNING] `rustc --crate-name build_script_build --edition=2015 build.rs [..]--target [ALT_TARGET] [..]", |
| ) |
| .with_stderr_contains("[RUNNING] `rustc --crate-name build_script_build --edition=2015 build.rs [..]") |
| .with_stderr_contains( |
| "[RUNNING] `rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--target [ALT_TARGET] [..]", |
| ) |
| .with_stderr_contains( |
| "[RUNNING] `rustc --crate-name bar --edition=2015 bar/src/main.rs [..]--target [ALT_TARGET] [..]", |
| ) |
| .with_stderr_contains( |
| "[RUNNING] `rustc --crate-name foo [..]--target [ALT_TARGET] [..]", |
| ) |
| .run(); |
| } |
| |
| #[cargo_test] |
| // TODO(ST): rename bar (dependency) to something else and un-ignore this with RFC-3176 |
| #[cfg_attr(target_env = "msvc", ignore = "msvc not working")] |
| fn profile_override_basic() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.1" |
| edition = "2015" |
| authors = [] |
| |
| [build-dependencies] |
| bar = { path = "bar", artifact = "bin" } |
| |
| [dependencies] |
| bar = { path = "bar", artifact = "bin" } |
| |
| [profile.dev.build-override] |
| opt-level = 1 |
| |
| [profile.dev] |
| opt-level = 3 |
| "#, |
| ) |
| .file("build.rs", "fn main() {}") |
| .file("src/lib.rs", "") |
| .file("bar/Cargo.toml", &basic_bin_manifest("bar")) |
| .file("bar/src/main.rs", "fn main() {}") |
| .file("bar/src/lib.rs", "pub fn bar() {}") |
| .build(); |
| |
| p.cargo("build -v -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data( |
| str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) |
| [COMPILING] foo v0.0.1 ([ROOT]/foo) |
| [RUNNING] `rustc --crate-name build_script_build [..] -C opt-level=1 [..]` |
| [RUNNING] `rustc --crate-name bar --edition=2015 bar/src/main.rs [..] -C opt-level=3 [..]` |
| [RUNNING] `rustc --crate-name bar --edition=2015 bar/src/main.rs [..] -C opt-level=1 [..]` |
| [RUNNING] `rustc --crate-name bar --edition=2015 bar/src/lib.rs [..] -C opt-level=1 [..]` |
| [RUNNING] `rustc --crate-name bar --edition=2015 bar/src/lib.rs [..] -C opt-level=3 [..]` |
| [RUNNING] `rustc --crate-name foo [..] -C opt-level=3 [..]` |
| [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` |
| [FINISHED] `dev` profile [optimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]] |
| .unordered(), |
| ) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn dependencies_of_dependencies_work_in_artifacts() { |
| Package::new("baz", "1.0.0") |
| .file("src/lib.rs", "pub fn baz() {}") |
| .publish(); |
| |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [build-dependencies] |
| bar = { path = "bar/", artifact = "bin" } |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .file( |
| "build.rs", |
| r#" |
| fn main() { |
| std::process::Command::new(std::env::var("CARGO_BIN_FILE_BAR").expect("BAR present")).status().unwrap(); |
| } |
| "#, |
| ) |
| .file( |
| "bar/Cargo.toml", |
| r#" |
| [package] |
| name = "bar" |
| version = "0.5.0" |
| edition = "2015" |
| authors = [] |
| |
| [dependencies] |
| baz = "1.0.0" |
| "#, |
| ) |
| .file("bar/src/lib.rs", r#"pub fn bar() {baz::baz()}"#) |
| .file("bar/src/main.rs", r#"fn main() {bar::bar()}"#) |
| .build(); |
| p.cargo("build -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .run(); |
| |
| // cargo tree sees artifacts as the dependency kind they are in and doesn't do anything special with it. |
| p.cargo("tree -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stdout_data(str![[r#" |
| foo v0.0.0 ([ROOT]/foo) |
| [build-dependencies] |
| └── bar v0.5.0 ([ROOT]/foo/bar) |
| └── baz v1.0.0 |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn artifact_dep_target_specified() { |
| if cross_compile::disabled() { |
| return; |
| } |
| let target = cross_compile::alternate(); |
| |
| let p = project() |
| .file( |
| "Cargo.toml", |
| &r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| authors = [] |
| resolver = "2" |
| edition = "2015" |
| |
| [dependencies] |
| bindep = { path = "bindep", artifact = "bin", target = "$TARGET" } |
| "# |
| .replace("$TARGET", target), |
| ) |
| .file("src/lib.rs", "") |
| .file("bindep/Cargo.toml", &basic_manifest("bindep", "0.0.0")) |
| .file("bindep/src/main.rs", "fn main() {}") |
| .build(); |
| |
| p.cargo("check -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [COMPILING] bindep v0.0.0 ([ROOT]/foo/bindep) |
| [CHECKING] foo v0.0.0 ([ROOT]/foo) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .with_status(0) |
| .run(); |
| |
| p.cargo("tree -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stdout_data(str![[r#" |
| foo v0.0.0 ([ROOT]/foo) |
| └── bindep v0.0.0 ([ROOT]/foo/bindep) |
| |
| "#]]) |
| .with_status(0) |
| .run(); |
| } |
| |
| /// From issue #10593 |
| /// The case where: |
| /// * artifact dep is { target = <specified> } |
| /// * dependency of that artifact dependency specifies the same target |
| /// * the target is not activated. |
| #[cargo_test] |
| fn dep_of_artifact_dep_same_target_specified() { |
| if cross_compile::disabled() { |
| return; |
| } |
| let target = cross_compile::alternate(); |
| let p = project() |
| .file( |
| "Cargo.toml", |
| &format!( |
| r#" |
| [package] |
| name = "foo" |
| version = "0.1.0" |
| edition = "2015" |
| resolver = "2" |
| |
| [dependencies] |
| bar = {{ path = "bar", artifact = "bin", target = "{target}" }} |
| "#, |
| ), |
| ) |
| .file("src/lib.rs", "") |
| .file( |
| "bar/Cargo.toml", |
| &format!( |
| r#" |
| [package] |
| name = "bar" |
| version = "0.1.0" |
| |
| [target.{target}.dependencies] |
| baz = {{ path = "../baz" }} |
| "#, |
| ), |
| ) |
| .file("bar/src/main.rs", "fn main() {}") |
| .file( |
| "baz/Cargo.toml", |
| r#" |
| [package] |
| name = "baz" |
| version = "0.1.0" |
| |
| "#, |
| ) |
| .file("baz/src/lib.rs", "") |
| .build(); |
| |
| p.cargo("check -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 2 packages to latest compatible versions |
| [COMPILING] baz v0.1.0 ([ROOT]/foo/baz) |
| [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) |
| [CHECKING] foo v0.1.0 ([ROOT]/foo) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .with_status(0) |
| .run(); |
| |
| p.cargo("tree -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stdout_data( |
| r#"... |
| foo v0.1.0 ([ROOT]/foo) |
| └── bar v0.1.0 ([ROOT]/foo/bar) |
| └── baz v0.1.0 ([ROOT]/foo/baz) |
| "#, |
| ) |
| .with_status(0) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn targets_are_picked_up_from_non_workspace_artifact_deps() { |
| if cross_compile::disabled() { |
| return; |
| } |
| let target = cross_compile::alternate(); |
| Package::new("artifact", "1.0.0") |
| .file("src/main.rs", r#"fn main() {}"#) |
| .file("src/lib.rs", r#"pub fn lib() {}"#) |
| .publish(); |
| |
| let mut dep = registry::Dependency::new("artifact", "1.0.0"); |
| Package::new("uses-artifact", "1.0.0") |
| .schema_version(3) |
| .file( |
| "src/lib.rs", |
| r#"pub fn uses_artifact() { let _b = include_bytes!(env!("CARGO_BIN_FILE_ARTIFACT")); }"#, |
| ) |
| .add_dep(dep.artifact("bin", Some(target.to_string()))) |
| .publish(); |
| |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| |
| [dependencies] |
| uses-artifact = { version = "1.0.0" } |
| "#, |
| ) |
| .file( |
| "src/lib.rs", |
| r#"pub fn foo() { uses_artifact::uses_artifact(); }"#, |
| ) |
| .build(); |
| |
| p.cargo("build -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn index_version_filtering() { |
| if cross_compile::disabled() { |
| return; |
| } |
| let target = cross_compile::alternate(); |
| |
| Package::new("artifact", "1.0.0") |
| .file("src/main.rs", r#"fn main() {}"#) |
| .file("src/lib.rs", r#"pub fn lib() {}"#) |
| .publish(); |
| |
| let mut dep = registry::Dependency::new("artifact", "1.0.0"); |
| |
| Package::new("bar", "1.0.0").publish(); |
| Package::new("bar", "1.0.1") |
| .schema_version(3) |
| .add_dep(dep.artifact("bin", Some(target.to_string()))) |
| .publish(); |
| |
| // Verify that without `-Zbindeps` that it does not use 1.0.1. |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.1.0" |
| edition = "2015" |
| |
| [dependencies] |
| bar = "1.0" |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .build(); |
| |
| p.cargo("tree") |
| .with_stdout_data(str![[r#" |
| foo v0.1.0 ([ROOT]/foo) |
| └── bar v1.0.0 |
| |
| "#]]) |
| .run(); |
| |
| // And with -Zbindeps it can use 1.0.1. |
| p.cargo("update -Zbindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [UPDATING] `dummy-registry` index |
| [LOCKING] 2 packages to latest compatible versions |
| [ADDING] artifact v1.0.0 |
| [UPDATING] bar v1.0.0 -> v1.0.1 |
| |
| "#]]) |
| .run(); |
| |
| // And without -Zbindeps, now that 1.0.1 is in Cargo.lock, it should fail. |
| p.cargo("check") |
| .with_status(101) |
| .with_stderr_data(str![[r#" |
| [UPDATING] `dummy-registry` index |
| [ERROR] failed to select a version for the requirement `bar = "^1.0"` (locked to 1.0.1) |
| candidate versions found which didn't match: 1.0.0 |
| location searched: `dummy-registry` index (which is replacing registry `crates-io`) |
| required by package `foo v0.1.0 ([ROOT]/foo)` |
| perhaps a crate was updated and forgotten to be re-vendored? |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn proc_macro_in_artifact_dep() { |
| // Forcing FeatureResolver to check a proc-macro for a dependency behind a |
| // target dependency. |
| if cross_compile::disabled() { |
| return; |
| } |
| Package::new("pm", "1.0.0") |
| .file("src/lib.rs", "") |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "pm" |
| version = "1.0.0" |
| edition = "2015" |
| |
| [lib] |
| proc-macro = true |
| |
| "#, |
| ) |
| .publish(); |
| let alternate = cross_compile::alternate(); |
| Package::new("bin-uses-pm", "1.0.0") |
| .target_dep("pm", "1.0", alternate) |
| .file("src/main.rs", "fn main() {}") |
| .publish(); |
| // Simulate a network error downloading the proc-macro. |
| std::fs::remove_file(cargo_test_support::paths::root().join("dl/pm/1.0.0/download")).unwrap(); |
| let p = project() |
| .file( |
| "Cargo.toml", |
| &format!( |
| r#" |
| [package] |
| name = "foo" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| bin-uses-pm = {{ version = "1.0", artifact = "bin", target = "{alternate}"}} |
| "# |
| ), |
| ) |
| .file("src/lib.rs", "") |
| .build(); |
| |
| p.cargo("check -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data( |
| r#"... |
| [UPDATING] `dummy-registry` index |
| [LOCKING] 2 packages to latest compatible versions |
| [DOWNLOADING] crates ... |
| [ERROR] failed to download from `[ROOTURL]/dl/pm/1.0.0/download` |
| |
| Caused by: |
| [37] Could[..]t read a file:// file (Couldn't open file [ROOT]/dl/pm/1.0.0/download) |
| "#, |
| ) |
| .with_status(101) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn allow_dep_renames_with_multiple_versions() { |
| Package::new("bar", "1.0.0") |
| .file("src/main.rs", r#"fn main() {println!("1.0.0")}"#) |
| .publish(); |
| |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [build-dependencies] |
| bar = { path = "bar/", artifact = "bin" } |
| bar_stable = { package = "bar", version = "1.0.0", artifact = "bin" } |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .file( |
| "build.rs", |
| r#" |
| fn main() { |
| std::process::Command::new(std::env::var("CARGO_BIN_FILE_BAR").expect("BAR present")).status().unwrap(); |
| std::process::Command::new(std::env::var("CARGO_BIN_FILE_BAR_STABLE_bar").expect("BAR STABLE present")).status().unwrap(); |
| } |
| "#, |
| ) |
| .file("bar/Cargo.toml", &basic_bin_manifest("bar")) |
| .file("bar/src/main.rs", r#"fn main() {println!("0.5.0")}"#) |
| .build(); |
| p.cargo("check -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data( |
| str![[r#" |
| [UPDATING] `dummy-registry` index |
| [LOCKING] 2 packages to latest compatible versions |
| [DOWNLOADING] crates ... |
| [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) |
| [COMPILING] bar v1.0.0 |
| [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) |
| [COMPILING] foo v0.0.0 ([ROOT]/foo) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]] |
| .unordered(), |
| ) |
| .run(); |
| let build_script_output = build_script_output_string(&p, "foo"); |
| assert_e2e().eq( |
| &build_script_output, |
| str![[r#" |
| 0.5.0 |
| 1.0.0 |
| |
| "#]], |
| ); |
| } |
| |
| #[cargo_test] |
| fn allow_artifact_and_non_artifact_dependency_to_same_crate_if_these_are_not_the_same_dep_kind() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [build-dependencies] |
| bar = { path = "bar/", artifact = "bin", lib = false } |
| |
| [dependencies] |
| bar = { path = "bar/" } |
| "#, |
| ) |
| .file("src/lib.rs", r#" |
| pub fn foo() { |
| bar::doit(); |
| assert!(option_env!("CARGO_BIN_FILE_BAR").is_none()); |
| }"#) |
| .file( |
| "build.rs", |
| r#"fn main() { |
| println!("{}", std::env::var("CARGO_BIN_FILE_BAR").expect("CARGO_BIN_FILE_BAR")); |
| println!("{}", std::env::var("CARGO_BIN_FILE_BAR_bar").expect("CARGO_BIN_FILE_BAR_bar")); |
| }"#, |
| ) |
| .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) |
| .file("bar/src/lib.rs", "pub fn doit() {}") |
| .file("bar/src/main.rs", "fn main() {}") |
| .build(); |
| p.cargo("build -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) |
| [COMPILING] foo v0.0.0 ([ROOT]/foo) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn prevent_no_lib_warning_with_artifact_dependencies() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [dependencies] |
| bar = { path = "bar/", artifact = "bin" } |
| "#, |
| ) |
| .file( |
| "src/lib.rs", |
| r#"pub fn foo() { let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); }"#, |
| ) |
| .file("bar/Cargo.toml", &basic_bin_manifest("bar")) |
| .file("bar/src/main.rs", "fn main() {}") |
| .build(); |
| p.cargo("check -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) |
| [CHECKING] foo v0.0.0 ([ROOT]/foo) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn show_no_lib_warning_with_artifact_dependencies_that_have_no_lib_but_lib_true() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [build-dependencies] |
| bar = { path = "bar/", artifact = "bin" } |
| |
| [dependencies] |
| bar = { path = "bar/", artifact = "bin", lib = true } |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .file("src/build.rs", "fn main() {}") |
| .file("bar/Cargo.toml", &basic_bin_manifest("bar")) |
| .file("bar/src/main.rs", "fn main() {}") |
| .build(); |
| p.cargo("check -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [WARNING] foo v0.0.0 ([ROOT]/foo) ignoring invalid dependency `bar` which is missing a lib target |
| [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) |
| [CHECKING] foo v0.0.0 ([ROOT]/foo) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn resolver_2_build_dep_without_lib() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| authors = [] |
| edition = "2021" |
| |
| [build-dependencies] |
| bar = { path = "bar/", artifact = "bin" } |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .file("build.rs", r#" |
| fn main() { |
| let bar: std::path::PathBuf = std::env::var("CARGO_BIN_FILE_BAR").expect("CARGO_BIN_FILE_BAR").into(); |
| assert!(&bar.is_file()); |
| }"#) |
| .file("bar/Cargo.toml", &basic_bin_manifest("bar")) |
| .file("bar/src/main.rs", "fn main() {}") |
| .build(); |
| p.cargo("check -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn check_missing_crate_type_in_package_fails() { |
| for crate_type in &["cdylib", "staticlib", "bin"] { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| &format!( |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| |
| [dependencies] |
| bar = {{ path = "bar/", artifact = "{}" }} |
| "#, |
| crate_type |
| ), |
| ) |
| .file("src/lib.rs", "") |
| .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) //no bin, just rlib |
| .file("bar/src/lib.rs", "") |
| .build(); |
| p.cargo("check -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_status(101) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [ERROR] dependency `bar` in package `foo` requires a [..] artifact to be present. |
| |
| "#]]) |
| .run(); |
| } |
| } |
| |
| #[cargo_test] |
| fn check_target_equals_target_in_non_build_dependency_errors() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [dependencies] |
| bar = { path = "bar/", artifact = "bin", target = "target" } |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) |
| .file("bar/src/main.rs", "fn main() {}") |
| .build(); |
| p.cargo("check -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_status(101) |
| .with_stderr_data(str![[r#" |
| [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` |
| |
| Caused by: |
| `target = "target"` in normal- or dev-dependencies has no effect (bar) |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn env_vars_and_build_products_for_various_build_targets() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [lib] |
| doctest = true |
| |
| [build-dependencies] |
| bar = { path = "bar/", artifact = ["cdylib", "staticlib"] } |
| |
| [dependencies] |
| bar = { path = "bar/", artifact = "bin", lib = true } |
| |
| [dev-dependencies] |
| bar = { path = "bar/", artifact = "bin:baz" } |
| "#, |
| ) |
| .file("build.rs", r#" |
| fn main() { |
| let file: std::path::PathBuf = std::env::var("CARGO_CDYLIB_FILE_BAR").expect("CARGO_CDYLIB_FILE_BAR").into(); |
| assert!(&file.is_file()); |
| |
| let file: std::path::PathBuf = std::env::var("CARGO_STATICLIB_FILE_BAR").expect("CARGO_STATICLIB_FILE_BAR").into(); |
| assert!(&file.is_file()); |
| |
| assert!(std::env::var("CARGO_BIN_FILE_BAR").is_err()); |
| assert!(std::env::var("CARGO_BIN_FILE_BAR_baz").is_err()); |
| } |
| "#) |
| .file( |
| "src/lib.rs", |
| r#" |
| //! ``` |
| //! bar::c(); |
| //! env!("CARGO_BIN_DIR_BAR"); |
| //! let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); |
| //! let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR_bar")); |
| //! let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR_baz")); |
| //! assert!(option_env!("CARGO_STATICLIB_FILE_BAR").is_none()); |
| //! assert!(option_env!("CARGO_CDYLIB_FILE_BAR").is_none()); |
| //! ``` |
| pub fn foo() { |
| bar::c(); |
| env!("CARGO_BIN_DIR_BAR"); |
| let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); |
| let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR_bar")); |
| let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR_baz")); |
| assert!(option_env!("CARGO_STATICLIB_FILE_BAR").is_none()); |
| assert!(option_env!("CARGO_CDYLIB_FILE_BAR").is_none()); |
| } |
| |
| #[cfg(test)] |
| #[test] |
| fn env_unit() { |
| env!("CARGO_BIN_DIR_BAR"); |
| let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); |
| let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR_bar")); |
| let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR_baz")); |
| assert!(option_env!("CARGO_STATICLIB_FILE_BAR").is_none()); |
| assert!(option_env!("CARGO_CDYLIB_FILE_BAR").is_none()); |
| } |
| "#, |
| ) |
| .file( |
| "tests/main.rs", |
| r#" |
| #[test] |
| fn env_integration() { |
| env!("CARGO_BIN_DIR_BAR"); |
| let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); |
| let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR_bar")); |
| let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR_baz")); |
| }"#, |
| ) |
| .file("build.rs", "fn main() {}") |
| .file( |
| "bar/Cargo.toml", |
| r#" |
| [package] |
| name = "bar" |
| version = "0.5.0" |
| edition = "2015" |
| authors = [] |
| |
| [lib] |
| crate-type = ["staticlib", "cdylib", "rlib"] |
| |
| [[bin]] |
| name = "bar" |
| |
| [[bin]] |
| name = "baz" |
| "#, |
| ) |
| .file("bar/src/lib.rs", r#"pub extern "C" fn c() {}"#) |
| .file("bar/src/main.rs", "fn main() {}") |
| .build(); |
| p.cargo("test -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) |
| [COMPILING] foo v0.0.0 ([ROOT]/foo) |
| [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) |
| [RUNNING] tests/main.rs (target/debug/deps/main-[HASH][EXE]) |
| [DOCTEST] foo |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn publish_artifact_dep() { |
| let registry = RegistryBuilder::new().http_api().http_index().build(); |
| |
| Package::new("bar", "1.0.0").publish(); |
| Package::new("baz", "1.0.0").publish(); |
| |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.1.0" |
| edition = "2015" |
| authors = [] |
| license = "MIT" |
| description = "foo" |
| documentation = "foo" |
| homepage = "foo" |
| repository = "foo" |
| resolver = "2" |
| |
| [dependencies] |
| bar = { version = "1.0", artifact = "bin", lib = true } |
| |
| [build-dependencies] |
| baz = { version = "1.0", artifact = ["bin:a", "cdylib", "staticlib"], target = "target" } |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .build(); |
| |
| p.cargo("publish -Z bindeps --no-verify") |
| .replace_crates_io(registry.index_url()) |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [UPDATING] crates.io index |
| [PACKAGING] foo v0.1.0 ([ROOT]/foo) |
| [PACKAGED] 3 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) |
| [UPLOADING] foo v0.1.0 ([ROOT]/foo) |
| [UPLOADED] foo v0.1.0 to registry `crates-io` |
| [NOTE] waiting for `foo v0.1.0` to be available at registry `crates-io`. |
| You may press ctrl-c to skip waiting; the crate should be available shortly. |
| [PUBLISHED] foo v0.1.0 at registry `crates-io` |
| |
| "#]]) |
| .run(); |
| |
| publish::validate_upload_with_contents( |
| r#" |
| { |
| "authors": [], |
| "badges": {}, |
| "categories": [], |
| "deps": [{ |
| "artifact": ["bin"], |
| "default_features": true, |
| "features": [], |
| "kind": "normal", |
| "lib": true, |
| "name": "bar", |
| "optional": false, |
| "target": null, |
| "version_req": "^1.0" |
| }, |
| { |
| "artifact": [ |
| "bin:a", |
| "cdylib", |
| "staticlib" |
| ], |
| "bindep_target": "target", |
| "default_features": true, |
| "features": [], |
| "kind": "build", |
| "name": "baz", |
| "optional": false, |
| "target": null, |
| "version_req": "^1.0" |
| } |
| ], |
| "description": "foo", |
| "documentation": "foo", |
| "features": {}, |
| "homepage": "foo", |
| "keywords": [], |
| "license": "MIT", |
| "license_file": null, |
| "links": null, |
| "name": "foo", |
| "readme": null, |
| "readme_file": null, |
| "repository": "foo", |
| "rust_version": null, |
| "vers": "0.1.0" |
| } |
| "#, |
| "foo-0.1.0.crate", |
| &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs"], |
| [( |
| "Cargo.toml", |
| str![[r##" |
| # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO |
| # |
| # When uploading crates to the registry Cargo will automatically |
| # "normalize" Cargo.toml files for maximal compatibility |
| # with all versions of Cargo and also rewrite `path` dependencies |
| # to registry (e.g., crates.io) dependencies. |
| # |
| # If you are reading this file be aware that the original Cargo.toml |
| # will likely look very different (and much more reasonable). |
| # See Cargo.toml.orig for the original contents. |
| |
| [package] |
| edition = "2015" |
| name = "foo" |
| version = "0.1.0" |
| authors = [] |
| build = false |
| autolib = false |
| autobins = false |
| autoexamples = false |
| autotests = false |
| autobenches = false |
| description = "foo" |
| homepage = "foo" |
| documentation = "foo" |
| readme = false |
| license = "MIT" |
| repository = "foo" |
| resolver = "2" |
| |
| [lib] |
| name = "foo" |
| path = "src/lib.rs" |
| |
| [dependencies.bar] |
| version = "1.0" |
| artifact = ["bin"] |
| lib = true |
| |
| [build-dependencies.baz] |
| version = "1.0" |
| artifact = [ |
| "bin:a", |
| "cdylib", |
| "staticlib", |
| ] |
| target = "target" |
| |
| "##]], |
| )], |
| ); |
| } |
| |
| #[cargo_test] |
| fn doc_lib_true() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.1" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [dependencies.bar] |
| path = "bar" |
| artifact = "bin" |
| lib = true |
| "#, |
| ) |
| .file("src/lib.rs", "extern crate bar; pub fn foo() {}") |
| .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) |
| .file("bar/src/lib.rs", "pub fn bar() {}") |
| .file("bar/src/main.rs", "fn main() {}") |
| .build(); |
| |
| p.cargo("doc -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) |
| [DOCUMENTING] bar v0.0.1 ([ROOT]/foo/bar) |
| [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| [GENERATED] [ROOT]/foo/target/doc/foo/index.html |
| |
| "#]]) |
| .run(); |
| |
| assert!(p.root().join("target/doc").is_dir()); |
| assert!(p.root().join("target/doc/foo/index.html").is_file()); |
| assert!(p.root().join("target/doc/bar/index.html").is_file()); |
| |
| // Verify that it emits rmeta for the bin and lib dependency. |
| assert_eq!(p.glob("target/debug/artifact/*.rlib").count(), 0); |
| assert_eq!(p.glob("target/debug/deps/libbar-*.rmeta").count(), 2); |
| |
| p.cargo("doc -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| [GENERATED] [ROOT]/foo/target/doc/foo/index.html |
| |
| "#]]) |
| .run(); |
| |
| assert!(p.root().join("target/doc").is_dir()); |
| assert!(p.root().join("target/doc/foo/index.html").is_file()); |
| assert!(p.root().join("target/doc/bar/index.html").is_file()); |
| } |
| |
| #[cargo_test] |
| fn rustdoc_works_on_libs_with_artifacts_and_lib_false() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.1" |
| edition = "2015" |
| authors = [] |
| resolver = "2" |
| |
| [dependencies.bar] |
| path = "bar" |
| artifact = ["bin", "staticlib", "cdylib"] |
| "#, |
| ) |
| .file( |
| "src/lib.rs", |
| r#" |
| pub fn foo() { |
| env!("CARGO_BIN_DIR_BAR"); |
| let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); |
| let _b = include_bytes!(env!("CARGO_CDYLIB_FILE_BAR")); |
| let _b = include_bytes!(env!("CARGO_CDYLIB_FILE_BAR_bar")); |
| let _b = include_bytes!(env!("CARGO_STATICLIB_FILE_BAR")); |
| let _b = include_bytes!(env!("CARGO_STATICLIB_FILE_BAR_bar")); |
| }"#, |
| ) |
| .file( |
| "bar/Cargo.toml", |
| r#" |
| [package] |
| name = "bar" |
| version = "0.5.0" |
| edition = "2015" |
| authors = [] |
| |
| [lib] |
| crate-type = ["staticlib", "cdylib"] |
| "#, |
| ) |
| .file("bar/src/lib.rs", "pub fn bar() {}") |
| .file("bar/src/main.rs", "fn main() {}") |
| .build(); |
| |
| p.cargo("doc -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) |
| [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| [GENERATED] [ROOT]/foo/target/doc/foo/index.html |
| |
| "#]]) |
| .run(); |
| |
| assert!(p.root().join("target/doc").is_dir()); |
| assert!(p.root().join("target/doc/foo/index.html").is_file()); |
| assert!( |
| !p.root().join("target/doc/bar/index.html").is_file(), |
| "bar is not a lib dependency and thus remains undocumented" |
| ); |
| } |
| |
| fn assert_artifact_executable_output( |
| p: &Project, |
| target_name: &str, |
| dep_name: &str, |
| bin_name: &str, |
| ) { |
| if cfg!(target_env = "msvc") { |
| assert_eq!( |
| p.glob(format!( |
| "target/{}/deps/artifact/{}-*/bin/{}{}", |
| target_name, |
| dep_name, |
| bin_name, |
| std::env::consts::EXE_SUFFIX |
| )) |
| .count(), |
| 1, |
| "artifacts are placed into their own output directory to not possibly clash" |
| ); |
| } else { |
| assert_eq!( |
| p.glob(format!( |
| "target/{}/deps/artifact/{}-*/bin/{}-*{}", |
| target_name, |
| dep_name, |
| bin_name, |
| std::env::consts::EXE_SUFFIX |
| )) |
| .filter_map(Result::ok) |
| .filter(|f| f.extension().map_or(true, |ext| ext != "o" && ext != "d")) |
| .count(), |
| 1, |
| "artifacts are placed into their own output directory to not possibly clash" |
| ); |
| } |
| } |
| |
| fn build_script_output_string(p: &Project, package_name: &str) -> String { |
| let paths = p |
| .glob(format!("target/debug/build/{}-*/output", package_name)) |
| .collect::<Result<Vec<_>, _>>() |
| .unwrap(); |
| assert_eq!(paths.len(), 1); |
| std::fs::read_to_string(&paths[0]).unwrap() |
| } |
| |
| #[cargo_test] |
| fn build_script_features_for_shared_dependency() { |
| // When a build script is built and run, its features should match. Here: |
| // |
| // foo |
| // -> artifact on d1 with target |
| // -> common with features f1 |
| // |
| // d1 |
| // -> common with features f2 |
| // |
| // common has features f1 and f2, with a build script. |
| // |
| // When common is built as a dependency of d1, it should have features |
| // `f2` (for the library and the build script). |
| // |
| // When common is built as a dependency of foo, it should have features |
| // `f1` (for the library and the build script). |
| if cross_compile::disabled() { |
| return; |
| } |
| let target = cross_compile::alternate(); |
| let p = project() |
| .file( |
| "Cargo.toml", |
| &r#" |
| [package] |
| name = "foo" |
| version = "0.0.1" |
| edition = "2015" |
| resolver = "2" |
| |
| [dependencies] |
| d1 = { path = "d1", artifact = "bin", target = "$TARGET" } |
| common = { path = "common", features = ["f1"] } |
| "# |
| .replace("$TARGET", target), |
| ) |
| .file( |
| "src/main.rs", |
| r#" |
| fn main() { |
| let _b = include_bytes!(env!("CARGO_BIN_FILE_D1")); |
| common::f1(); |
| } |
| "#, |
| ) |
| .file( |
| "d1/Cargo.toml", |
| r#" |
| [package] |
| name = "d1" |
| version = "0.0.1" |
| edition = "2015" |
| |
| [dependencies] |
| common = { path = "../common", features = ["f2"] } |
| "#, |
| ) |
| .file( |
| "d1/src/main.rs", |
| r#"fn main() { |
| common::f2(); |
| }"#, |
| ) |
| .file( |
| "common/Cargo.toml", |
| r#" |
| [package] |
| name = "common" |
| version = "0.0.1" |
| edition = "2015" |
| |
| [features] |
| f1 = [] |
| f2 = [] |
| "#, |
| ) |
| .file( |
| "common/src/lib.rs", |
| r#" |
| #[cfg(feature = "f1")] |
| pub fn f1() {} |
| |
| #[cfg(feature = "f2")] |
| pub fn f2() {} |
| "#, |
| ) |
| .file( |
| "common/build.rs", |
| &r#" |
| use std::env::var_os; |
| fn main() { |
| assert_eq!(var_os("CARGO_FEATURE_F1").is_some(), cfg!(feature="f1")); |
| assert_eq!(var_os("CARGO_FEATURE_F2").is_some(), cfg!(feature="f2")); |
| if std::env::var("TARGET").unwrap() == "$TARGET" { |
| assert!(var_os("CARGO_FEATURE_F1").is_none()); |
| assert!(var_os("CARGO_FEATURE_F2").is_some()); |
| } else { |
| assert!(var_os("CARGO_FEATURE_F1").is_some()); |
| assert!(var_os("CARGO_FEATURE_F2").is_none()); |
| } |
| } |
| "# |
| .replace("$TARGET", target), |
| ) |
| .build(); |
| |
| p.cargo("build -Z bindeps -v") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn calc_bin_artifact_fingerprint() { |
| // See rust-lang/cargo#10527 |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.1.0" |
| edition = "2015" |
| resolver = "2" |
| |
| [dependencies] |
| bar = { path = "bar/", artifact = "bin" } |
| "#, |
| ) |
| .file( |
| "src/main.rs", |
| r#" |
| fn main() { |
| let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); |
| } |
| "#, |
| ) |
| .file("bar/Cargo.toml", &basic_bin_manifest("bar")) |
| .file("bar/src/main.rs", r#"fn main() { println!("foo") }"#) |
| .build(); |
| p.cargo("check -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) |
| [CHECKING] foo v0.1.0 ([ROOT]/foo) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| |
| p.change_file("bar/src/main.rs", r#"fn main() { println!("bar") }"#); |
| // Change in artifact bin dep `bar` propagates to `foo`, triggering recompile. |
| p.cargo("check -v -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [DIRTY] bar v0.5.0 ([ROOT]/foo/bar): the file `bar/src/main.rs` has changed ([..]) |
| [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) |
| [RUNNING] `rustc --crate-name bar [..]` |
| [DIRTY] foo v0.1.0 ([ROOT]/foo): the dependency bar was rebuilt |
| [CHECKING] foo v0.1.0 ([ROOT]/foo) |
| [RUNNING] `rustc --crate-name foo [..]` |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| |
| // All units are fresh. No recompile. |
| p.cargo("check -v -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [FRESH] bar v0.5.0 ([ROOT]/foo/bar) |
| [FRESH] foo v0.1.0 ([ROOT]/foo) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn with_target_and_optional() { |
| // See rust-lang/cargo#10526 |
| if cross_compile::disabled() { |
| return; |
| } |
| let target = cross_compile::alternate(); |
| let p = project() |
| .file( |
| "Cargo.toml", |
| &r#" |
| [package] |
| name = "foo" |
| version = "0.0.1" |
| edition = "2021" |
| [dependencies] |
| d1 = { path = "d1", artifact = "bin", optional = true, target = "$TARGET" } |
| "# |
| .replace("$TARGET", target), |
| ) |
| .file( |
| "src/main.rs", |
| r#" |
| fn main() { |
| let _b = include_bytes!(env!("CARGO_BIN_FILE_D1")); |
| } |
| "#, |
| ) |
| .file( |
| "d1/Cargo.toml", |
| r#" |
| [package] |
| name = "d1" |
| version = "0.0.1" |
| edition = "2021" |
| "#, |
| ) |
| .file("d1/src/main.rs", "fn main() {}") |
| .build(); |
| |
| p.cargo("check -Z bindeps -F d1 -v") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [COMPILING] d1 v0.0.1 ([ROOT]/foo/d1) |
| [RUNNING] `rustc --crate-name d1 [..]--crate-type bin[..] |
| [CHECKING] foo v0.0.1 ([ROOT]/foo) |
| [RUNNING] `rustc --crate-name foo [..]--cfg[..]d1[..] |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn with_assumed_host_target_and_optional_build_dep() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.1" |
| edition = "2021" |
| [build-dependencies] |
| d1 = { path = "d1", artifact = "bin", optional = true, target = "target" } |
| "#, |
| ) |
| .file("src/main.rs", "fn main() {}") |
| .file( |
| "build.rs", |
| r#" |
| fn main() { |
| std::env::var("CARGO_BIN_FILE_D1").unwrap(); |
| } |
| "#, |
| ) |
| .file( |
| "d1/Cargo.toml", |
| r#" |
| [package] |
| name = "d1" |
| version = "0.0.1" |
| edition = "2021" |
| "#, |
| ) |
| .file("d1/src/main.rs", "fn main() {}") |
| .build(); |
| |
| p.cargo("check -Z bindeps -F d1 -v") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data( |
| str![[r#" |
| [LOCKING] 1 package to latest compatible version |
| [COMPILING] foo v0.0.1 ([ROOT]/foo) |
| [COMPILING] d1 v0.0.1 ([ROOT]/foo/d1) |
| [RUNNING] `rustc --crate-name build_script_build --edition=2021 [..]--crate-type bin[..] |
| [RUNNING] `rustc --crate-name d1 --edition=2021 [..]--crate-type bin[..] |
| [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` |
| [RUNNING] `rustc --crate-name foo --edition=2021 [..]--cfg[..]d1[..] |
| [FINISHED] `dev` profile [..] |
| |
| "#]] |
| .unordered(), |
| ) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn decouple_same_target_transitive_dep_from_artifact_dep() { |
| // See https://github.com/rust-lang/cargo/issues/11463 |
| let target = rustc_host(); |
| let p = project() |
| .file( |
| "Cargo.toml", |
| &format!( |
| r#" |
| [package] |
| name = "foo" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| a = {{ path = "a" }} |
| bar = {{ path = "bar", artifact = "bin", target = "{target}" }} |
| "# |
| ), |
| ) |
| .file( |
| "src/main.rs", |
| r#" |
| fn main() {} |
| "#, |
| ) |
| .file( |
| "bar/Cargo.toml", |
| r#" |
| [package] |
| name = "bar" |
| version = "0.1.0" |
| edition = "2015" |
| |
| [dependencies] |
| a = { path = "../a", features = ["feature"] } |
| "#, |
| ) |
| .file( |
| "bar/src/main.rs", |
| r#" |
| fn main() {} |
| "#, |
| ) |
| .file( |
| "a/Cargo.toml", |
| r#" |
| [package] |
| name = "a" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| b = { path = "../b" } |
| c = { path = "../c" } |
| |
| [features] |
| feature = ["c/feature"] |
| "#, |
| ) |
| .file( |
| "a/src/lib.rs", |
| r#" |
| use b::Trait as _; |
| |
| pub fn use_b_trait(x: &impl c::Trait) { |
| x.b(); |
| } |
| "#, |
| ) |
| .file( |
| "b/Cargo.toml", |
| r#" |
| [package] |
| name = "b" |
| version = "0.1.0" |
| edition = "2015" |
| |
| [dependencies] |
| c = { path = "../c" } |
| "#, |
| ) |
| .file( |
| "b/src/lib.rs", |
| r#" |
| pub trait Trait { |
| fn b(&self) {} |
| } |
| |
| impl<T: c::Trait> Trait for T {} |
| "#, |
| ) |
| .file( |
| "c/Cargo.toml", |
| r#" |
| [package] |
| name = "c" |
| version = "0.1.0" |
| edition = "2015" |
| |
| [features] |
| feature = [] |
| "#, |
| ) |
| .file( |
| "c/src/lib.rs", |
| r#" |
| pub trait Trait {} |
| "#, |
| ) |
| .build(); |
| p.cargo("build -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 4 packages to latest compatible versions |
| [COMPILING] c v0.1.0 ([ROOT]/foo/c) |
| [COMPILING] b v0.1.0 ([ROOT]/foo/b) |
| [COMPILING] a v0.1.0 ([ROOT]/foo/a) |
| [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) |
| [COMPILING] foo v0.1.0 ([ROOT]/foo) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn decouple_same_target_transitive_dep_from_artifact_dep_lib() { |
| // See https://github.com/rust-lang/cargo/issues/10837 |
| let target = rustc_host(); |
| let p = project() |
| .file( |
| "Cargo.toml", |
| &format!( |
| r#" |
| [package] |
| name = "foo" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| a = {{ path = "a" }} |
| b = {{ path = "b", features = ["feature"] }} |
| bar = {{ path = "bar", artifact = "bin", lib = true, target = "{target}" }} |
| "# |
| ), |
| ) |
| .file("src/lib.rs", "") |
| .file( |
| "bar/Cargo.toml", |
| r#" |
| [package] |
| name = "bar" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| a = { path = "../a", features = ["b"] } |
| b = { path = "../b" } |
| "#, |
| ) |
| .file("bar/src/lib.rs", "") |
| .file( |
| "bar/src/main.rs", |
| r#" |
| use b::Trait; |
| |
| fn main() { |
| a::A.b() |
| } |
| "#, |
| ) |
| .file( |
| "a/Cargo.toml", |
| r#" |
| [package] |
| name = "a" |
| version = "0.1.0" |
| edition = "2015" |
| |
| [dependencies] |
| b = { path = "../b", optional = true } |
| "#, |
| ) |
| .file( |
| "a/src/lib.rs", |
| r#" |
| pub struct A; |
| |
| #[cfg(feature = "b")] |
| impl b::Trait for A {} |
| "#, |
| ) |
| .file( |
| "b/Cargo.toml", |
| r#" |
| [package] |
| name = "b" |
| version = "0.1.0" |
| edition = "2015" |
| |
| [features] |
| feature = [] |
| "#, |
| ) |
| .file( |
| "b/src/lib.rs", |
| r#" |
| pub trait Trait { |
| fn b(&self) {} |
| } |
| "#, |
| ) |
| .build(); |
| p.cargo("build -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 3 packages to latest compatible versions |
| [COMPILING] b v0.1.0 ([ROOT]/foo/b) |
| [COMPILING] a v0.1.0 ([ROOT]/foo/a) |
| [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) |
| [COMPILING] foo v0.1.0 ([ROOT]/foo) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn decouple_same_target_transitive_dep_from_artifact_dep_and_proc_macro() { |
| let target = rustc_host(); |
| let p = project() |
| .file( |
| "Cargo.toml", |
| &format!( |
| r#" |
| [package] |
| name = "foo" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| c = {{ path = "c" }} |
| bar = {{ path = "bar", artifact = "bin", target = "{target}" }} |
| "# |
| ), |
| ) |
| .file("src/lib.rs", "") |
| .file( |
| "bar/Cargo.toml", |
| r#" |
| [package] |
| name = "bar" |
| version = "0.1.0" |
| edition = "2015" |
| |
| [dependencies] |
| b = { path = "../b" } |
| "#, |
| ) |
| .file("bar/src/main.rs", "fn main() {}") |
| .file( |
| "b/Cargo.toml", |
| r#" |
| [package] |
| name = "b" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| a = { path = "../a" } |
| |
| [lib] |
| proc-macro = true |
| "#, |
| ) |
| .file("b/src/lib.rs", "") |
| .file( |
| "c/Cargo.toml", |
| r#" |
| [package] |
| name = "c" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| d = { path = "../d", features = ["feature"] } |
| a = { path = "../a" } |
| |
| [lib] |
| proc-macro = true |
| "#, |
| ) |
| .file( |
| "c/src/lib.rs", |
| r#" |
| use a::Trait; |
| |
| fn _c() { |
| d::D.a() |
| } |
| "#, |
| ) |
| .file( |
| "a/Cargo.toml", |
| r#" |
| [package] |
| name = "a" |
| version = "0.1.0" |
| edition = "2015" |
| |
| [dependencies] |
| d = { path = "../d" } |
| "#, |
| ) |
| .file( |
| "a/src/lib.rs", |
| r#" |
| pub trait Trait { |
| fn a(&self) {} |
| } |
| |
| impl Trait for d::D {} |
| "#, |
| ) |
| .file( |
| "d/Cargo.toml", |
| r#" |
| [package] |
| name = "d" |
| version = "0.1.0" |
| edition = "2015" |
| |
| [features] |
| feature = [] |
| "#, |
| ) |
| .file("d/src/lib.rs", "pub struct D;") |
| .build(); |
| |
| p.cargo("build -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data( |
| str![[r#" |
| [LOCKING] 5 packages to latest compatible versions |
| [COMPILING] d v0.1.0 ([ROOT]/foo/d) |
| [COMPILING] a v0.1.0 ([ROOT]/foo/a) |
| [COMPILING] b v0.1.0 ([ROOT]/foo/b) |
| [COMPILING] c v0.1.0 ([ROOT]/foo/c) |
| [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) |
| [COMPILING] foo v0.1.0 ([ROOT]/foo) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..] |
| |
| "#]] |
| .unordered(), |
| ) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn same_target_artifact_dep_sharing() { |
| let target = rustc_host(); |
| let p = project() |
| .file( |
| "Cargo.toml", |
| &format!( |
| r#" |
| [package] |
| name = "foo" |
| version = "0.1.0" |
| edition = "2015" |
| |
| [dependencies] |
| a = {{ path = "a" }} |
| bar = {{ path = "bar", artifact = "bin", target = "{target}" }} |
| "# |
| ), |
| ) |
| .file("src/lib.rs", "") |
| .file( |
| "bar/Cargo.toml", |
| r#" |
| [package] |
| name = "bar" |
| version = "0.1.0" |
| edition = "2015" |
| |
| [dependencies] |
| a = { path = "../a" } |
| "#, |
| ) |
| .file( |
| "bar/src/main.rs", |
| r#" |
| fn main() {} |
| "#, |
| ) |
| .file( |
| "a/Cargo.toml", |
| r#" |
| [package] |
| name = "a" |
| version = "0.1.0" |
| edition = "2015" |
| "#, |
| ) |
| .file("a/src/lib.rs", "") |
| .build(); |
| p.cargo(&format!("build -Z bindeps --target {target}")) |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 2 packages to latest compatible versions |
| [COMPILING] a v0.1.0 ([ROOT]/foo/a) |
| [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) |
| [COMPILING] foo v0.1.0 ([ROOT]/foo) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn check_transitive_artifact_dependency_with_different_target() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "foo" |
| version = "0.0.0" |
| edition = "2015" |
| |
| [dependencies] |
| bar = { path = "bar/" } |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .file( |
| "bar/Cargo.toml", |
| r#" |
| [package] |
| name = "bar" |
| version = "0.0.0" |
| edition = "2015" |
| |
| [dependencies] |
| baz = { path = "baz/", artifact = "bin", target = "custom-target" } |
| "#, |
| ) |
| .file("bar/src/lib.rs", "") |
| .file( |
| "bar/baz/Cargo.toml", |
| r#" |
| [package] |
| name = "baz" |
| version = "0.0.0" |
| edition = "2015" |
| |
| [dependencies] |
| "#, |
| ) |
| .file("bar/baz/src/main.rs", "fn main() {}") |
| .build(); |
| |
| p.cargo("check -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .with_stderr_data(str![[r#" |
| [LOCKING] 2 packages to latest compatible versions |
| [ERROR] failed to determine target information for target `custom-target`. |
| Artifact dependency `baz` in package `bar v0.0.0 ([ROOT]/foo/bar)` requires building for `custom-target` |
| |
| Caused by: |
| failed to run `rustc` to learn about target-specific information |
| |
| Caused by: |
| process didn't exit successfully: `rustc [..] ([EXIT_STATUS]: 1) |
| --- stderr |
| ... |
| |
| |
| "#]]) |
| .with_status(101) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn build_only_specified_artifact_library() { |
| // Create a project with: |
| // - A crate `bar` with both `staticlib` and `cdylib` as crate-types. |
| // - A crate `foo` which depends on either the `staticlib` or `cdylib` artifact of bar, |
| // whose build-script simply checks which library artifacts are present. |
| let create_project = |artifact_lib| { |
| project() |
| .file( |
| "bar/Cargo.toml", |
| r#" |
| [package] |
| name = "bar" |
| version = "1.0.0" |
| |
| [lib] |
| crate-type = ["staticlib", "cdylib"] |
| "#, |
| ) |
| .file("bar/src/lib.rs", "") |
| .file( |
| "Cargo.toml", |
| &format!( |
| r#" |
| [package] |
| name = "foo" |
| version = "1.0.0" |
| |
| [build-dependencies] |
| bar = {{ path = "bar", artifact = "{artifact_lib}" }} |
| "#), |
| ) |
| .file("src/lib.rs", "") |
| .file( |
| "build.rs", |
| r#" |
| fn main() { |
| println!("cdylib present: {}", std::env::var_os("CARGO_CDYLIB_FILE_BAR").is_some()); |
| println!("staticlib present: {}", std::env::var_os("CARGO_STATICLIB_FILE_BAR").is_some()); |
| } |
| "#, |
| ) |
| .build() |
| }; |
| |
| let cdylib = create_project("cdylib"); |
| cdylib |
| .cargo("build -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .run(); |
| assert_e2e().eq( |
| &build_script_output_string(&cdylib, "foo"), |
| str![[r#" |
| cdylib present: true |
| staticlib present: false |
| |
| "#]], |
| ); |
| |
| let staticlib = create_project("staticlib"); |
| staticlib |
| .cargo("build -Z bindeps") |
| .masquerade_as_nightly_cargo(&["bindeps"]) |
| .run(); |
| assert_e2e().eq( |
| &build_script_output_string(&staticlib, "foo"), |
| str![[r#" |
| cdylib present: false |
| staticlib present: true |
| |
| "#]], |
| ); |
| } |