mirror of
https://github.com/rust-lang/cargo
synced 2024-08-25 10:35:53 +00:00
616 lines
16 KiB
Rust
616 lines
16 KiB
Rust
//! Tests for dep-info files. This includes the dep-info file Cargo creates in
|
|
//! the output directory, and the ones stored in the fingerprint.
|
|
|
|
use cargo_test_support::compare::assert_match_exact;
|
|
use cargo_test_support::paths::{self, CargoPathExt};
|
|
use cargo_test_support::registry::Package;
|
|
use cargo_test_support::{
|
|
basic_bin_manifest, basic_manifest, is_nightly, main_file, project, rustc_host, Project,
|
|
};
|
|
use filetime::FileTime;
|
|
use std::convert::TryInto;
|
|
use std::fs;
|
|
use std::path::Path;
|
|
use std::str;
|
|
|
|
// Helper for testing dep-info files in the fingerprint dir.
|
|
#[track_caller]
|
|
fn assert_deps(project: &Project, fingerprint: &str, test_cb: impl Fn(&Path, &[(u8, &str)])) {
|
|
let mut files = project
|
|
.glob(fingerprint)
|
|
.map(|f| f.expect("unwrap glob result"))
|
|
// Filter out `.json` entries.
|
|
.filter(|f| f.extension().is_none());
|
|
let info_path = files
|
|
.next()
|
|
.unwrap_or_else(|| panic!("expected 1 dep-info file at {}, found 0", fingerprint));
|
|
assert!(files.next().is_none(), "expected only 1 dep-info file");
|
|
let dep_info = fs::read(&info_path).unwrap();
|
|
let dep_info = &mut &dep_info[..];
|
|
let deps = (0..read_usize(dep_info))
|
|
.map(|_| {
|
|
(
|
|
read_u8(dep_info),
|
|
str::from_utf8(read_bytes(dep_info)).unwrap(),
|
|
)
|
|
})
|
|
.collect::<Vec<_>>();
|
|
test_cb(&info_path, &deps);
|
|
|
|
fn read_usize(bytes: &mut &[u8]) -> usize {
|
|
let ret = &bytes[..4];
|
|
*bytes = &bytes[4..];
|
|
|
|
u32::from_le_bytes(ret.try_into().unwrap()) as usize
|
|
}
|
|
|
|
fn read_u8(bytes: &mut &[u8]) -> u8 {
|
|
let ret = bytes[0];
|
|
*bytes = &bytes[1..];
|
|
ret
|
|
}
|
|
|
|
fn read_bytes<'a>(bytes: &mut &'a [u8]) -> &'a [u8] {
|
|
let n = read_usize(bytes);
|
|
let ret = &bytes[..n];
|
|
*bytes = &bytes[n..];
|
|
ret
|
|
}
|
|
}
|
|
|
|
fn assert_deps_contains(project: &Project, fingerprint: &str, expected: &[(u8, &str)]) {
|
|
assert_deps(project, fingerprint, |info_path, entries| {
|
|
for (e_kind, e_path) in expected {
|
|
let pattern = glob::Pattern::new(e_path).unwrap();
|
|
let count = entries
|
|
.iter()
|
|
.filter(|(kind, path)| kind == e_kind && pattern.matches(path))
|
|
.count();
|
|
if count != 1 {
|
|
panic!(
|
|
"Expected 1 match of {} {} in {:?}, got {}:\n{:#?}",
|
|
e_kind, e_path, info_path, count, entries
|
|
);
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn build_dep_info() {
|
|
let p = project()
|
|
.file("Cargo.toml", &basic_bin_manifest("foo"))
|
|
.file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
|
|
.build();
|
|
|
|
p.cargo("build").run();
|
|
|
|
let depinfo_bin_path = &p.bin("foo").with_extension("d");
|
|
|
|
assert!(depinfo_bin_path.is_file());
|
|
|
|
let depinfo = p.read_file(depinfo_bin_path.to_str().unwrap());
|
|
|
|
let bin_path = p.bin("foo");
|
|
let src_path = p.root().join("src").join("foo.rs");
|
|
if !depinfo.lines().any(|line| {
|
|
line.starts_with(&format!("{}:", bin_path.display()))
|
|
&& line.contains(src_path.to_str().unwrap())
|
|
}) {
|
|
panic!(
|
|
"Could not find {:?}: {:?} in {:?}",
|
|
bin_path, src_path, depinfo_bin_path
|
|
);
|
|
}
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn build_dep_info_lib() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[[example]]
|
|
name = "ex"
|
|
crate-type = ["lib"]
|
|
"#,
|
|
)
|
|
.file("build.rs", "fn main() {}")
|
|
.file("src/lib.rs", "")
|
|
.file("examples/ex.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build --example=ex").run();
|
|
assert!(p.example_lib("ex", "lib").with_extension("d").is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn build_dep_info_rlib() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[[example]]
|
|
name = "ex"
|
|
crate-type = ["rlib"]
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("examples/ex.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build --example=ex").run();
|
|
assert!(p.example_lib("ex", "rlib").with_extension("d").is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn build_dep_info_dylib() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[[example]]
|
|
name = "ex"
|
|
crate-type = ["dylib"]
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("examples/ex.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build --example=ex").run();
|
|
assert!(p.example_lib("ex", "dylib").with_extension("d").is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn dep_path_inside_target_has_correct_path() {
|
|
let p = project()
|
|
.file("Cargo.toml", &basic_bin_manifest("a"))
|
|
.file("target/debug/blah", "")
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
fn main() {
|
|
let x = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/target/debug/blah"));
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build").run();
|
|
|
|
let depinfo_path = &p.bin("a").with_extension("d");
|
|
|
|
assert!(depinfo_path.is_file(), "{:?}", depinfo_path);
|
|
|
|
let depinfo = p.read_file(depinfo_path.to_str().unwrap());
|
|
|
|
let bin_path = p.bin("a");
|
|
let target_debug_blah = Path::new("target").join("debug").join("blah");
|
|
if !depinfo.lines().any(|line| {
|
|
line.starts_with(&format!("{}:", bin_path.display()))
|
|
&& line.contains(target_debug_blah.to_str().unwrap())
|
|
}) {
|
|
panic!(
|
|
"Could not find {:?}: {:?} in {:?}",
|
|
bin_path, target_debug_blah, depinfo_path
|
|
);
|
|
}
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn no_rewrite_if_no_change() {
|
|
let p = project().file("src/lib.rs", "").build();
|
|
|
|
p.cargo("build").run();
|
|
let dep_info = p.root().join("target/debug/libfoo.d");
|
|
let metadata1 = dep_info.metadata().unwrap();
|
|
p.cargo("build").run();
|
|
let metadata2 = dep_info.metadata().unwrap();
|
|
|
|
assert_eq!(
|
|
FileTime::from_last_modification_time(&metadata1),
|
|
FileTime::from_last_modification_time(&metadata2),
|
|
);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn relative_depinfo_paths_ws() {
|
|
if !is_nightly() {
|
|
// -Z binary-dep-depinfo is unstable (https://github.com/rust-lang/rust/issues/63012)
|
|
return;
|
|
}
|
|
|
|
// Test relative dep-info paths in a workspace with --target with
|
|
// proc-macros and other dependency kinds.
|
|
Package::new("regdep", "0.1.0")
|
|
.file("src/lib.rs", "pub fn f() {}")
|
|
.publish();
|
|
Package::new("pmdep", "0.1.0")
|
|
.file("src/lib.rs", "pub fn f() {}")
|
|
.publish();
|
|
Package::new("bdep", "0.1.0")
|
|
.file("src/lib.rs", "pub fn f() {}")
|
|
.publish();
|
|
|
|
let p = project()
|
|
/*********** Workspace ***********/
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[workspace]
|
|
members = ["foo"]
|
|
"#,
|
|
)
|
|
/*********** Main Project ***********/
|
|
.file(
|
|
"foo/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
edition = "2018"
|
|
|
|
[dependencies]
|
|
pm = {path = "../pm"}
|
|
bar = {path = "../bar"}
|
|
regdep = "0.1"
|
|
|
|
[build-dependencies]
|
|
bdep = "0.1"
|
|
bar = {path = "../bar"}
|
|
"#,
|
|
)
|
|
.file(
|
|
"foo/src/main.rs",
|
|
r#"
|
|
pm::noop!{}
|
|
|
|
fn main() {
|
|
bar::f();
|
|
regdep::f();
|
|
}
|
|
"#,
|
|
)
|
|
.file("foo/build.rs", "fn main() { bdep::f(); }")
|
|
/*********** Proc Macro ***********/
|
|
.file(
|
|
"pm/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "pm"
|
|
version = "0.1.0"
|
|
edition = "2018"
|
|
|
|
[lib]
|
|
proc-macro = true
|
|
|
|
[dependencies]
|
|
pmdep = "0.1"
|
|
"#,
|
|
)
|
|
.file(
|
|
"pm/src/lib.rs",
|
|
r#"
|
|
extern crate proc_macro;
|
|
use proc_macro::TokenStream;
|
|
|
|
#[proc_macro]
|
|
pub fn noop(_item: TokenStream) -> TokenStream {
|
|
pmdep::f();
|
|
"".parse().unwrap()
|
|
}
|
|
"#,
|
|
)
|
|
/*********** Path Dependency `bar` ***********/
|
|
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
|
|
.file("bar/src/lib.rs", "pub fn f() {}")
|
|
.build();
|
|
|
|
let host = rustc_host();
|
|
p.cargo("build -Z binary-dep-depinfo --target")
|
|
.arg(&host)
|
|
.masquerade_as_nightly_cargo()
|
|
.with_stderr_contains("[COMPILING] foo [..]")
|
|
.run();
|
|
|
|
assert_deps_contains(
|
|
&p,
|
|
"target/debug/.fingerprint/pm-*/dep-lib-pm",
|
|
&[(0, "src/lib.rs"), (1, "debug/deps/libpmdep-*.rlib")],
|
|
);
|
|
|
|
assert_deps_contains(
|
|
&p,
|
|
&format!("target/{}/debug/.fingerprint/foo-*/dep-bin-foo", host),
|
|
&[
|
|
(0, "src/main.rs"),
|
|
(
|
|
1,
|
|
&format!(
|
|
"debug/deps/{}pm-*.{}",
|
|
paths::get_lib_prefix("proc-macro"),
|
|
paths::get_lib_extension("proc-macro")
|
|
),
|
|
),
|
|
(1, &format!("{}/debug/deps/libbar-*.rlib", host)),
|
|
(1, &format!("{}/debug/deps/libregdep-*.rlib", host)),
|
|
],
|
|
);
|
|
|
|
assert_deps_contains(
|
|
&p,
|
|
"target/debug/.fingerprint/foo-*/dep-build-script-build-script-build",
|
|
&[(0, "build.rs"), (1, "debug/deps/libbdep-*.rlib")],
|
|
);
|
|
|
|
// Make sure it stays fresh.
|
|
p.cargo("build -Z binary-dep-depinfo --target")
|
|
.arg(&host)
|
|
.masquerade_as_nightly_cargo()
|
|
.with_stderr("[FINISHED] dev [..]")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn relative_depinfo_paths_no_ws() {
|
|
if !is_nightly() {
|
|
// -Z binary-dep-depinfo is unstable (https://github.com/rust-lang/rust/issues/63012)
|
|
return;
|
|
}
|
|
|
|
// Test relative dep-info paths without a workspace with proc-macros and
|
|
// other dependency kinds.
|
|
Package::new("regdep", "0.1.0")
|
|
.file("src/lib.rs", "pub fn f() {}")
|
|
.publish();
|
|
Package::new("pmdep", "0.1.0")
|
|
.file("src/lib.rs", "pub fn f() {}")
|
|
.publish();
|
|
Package::new("bdep", "0.1.0")
|
|
.file("src/lib.rs", "pub fn f() {}")
|
|
.publish();
|
|
|
|
let p = project()
|
|
/*********** Main Project ***********/
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
edition = "2018"
|
|
|
|
[dependencies]
|
|
pm = {path = "pm"}
|
|
bar = {path = "bar"}
|
|
regdep = "0.1"
|
|
|
|
[build-dependencies]
|
|
bdep = "0.1"
|
|
bar = {path = "bar"}
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
pm::noop!{}
|
|
|
|
fn main() {
|
|
bar::f();
|
|
regdep::f();
|
|
}
|
|
"#,
|
|
)
|
|
.file("build.rs", "fn main() { bdep::f(); }")
|
|
/*********** Proc Macro ***********/
|
|
.file(
|
|
"pm/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "pm"
|
|
version = "0.1.0"
|
|
edition = "2018"
|
|
|
|
[lib]
|
|
proc-macro = true
|
|
|
|
[dependencies]
|
|
pmdep = "0.1"
|
|
"#,
|
|
)
|
|
.file(
|
|
"pm/src/lib.rs",
|
|
r#"
|
|
extern crate proc_macro;
|
|
use proc_macro::TokenStream;
|
|
|
|
#[proc_macro]
|
|
pub fn noop(_item: TokenStream) -> TokenStream {
|
|
pmdep::f();
|
|
"".parse().unwrap()
|
|
}
|
|
"#,
|
|
)
|
|
/*********** Path Dependency `bar` ***********/
|
|
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
|
|
.file("bar/src/lib.rs", "pub fn f() {}")
|
|
.build();
|
|
|
|
p.cargo("build -Z binary-dep-depinfo")
|
|
.masquerade_as_nightly_cargo()
|
|
.with_stderr_contains("[COMPILING] foo [..]")
|
|
.run();
|
|
|
|
assert_deps_contains(
|
|
&p,
|
|
"target/debug/.fingerprint/pm-*/dep-lib-pm",
|
|
&[(0, "src/lib.rs"), (1, "debug/deps/libpmdep-*.rlib")],
|
|
);
|
|
|
|
assert_deps_contains(
|
|
&p,
|
|
"target/debug/.fingerprint/foo-*/dep-bin-foo",
|
|
&[
|
|
(0, "src/main.rs"),
|
|
(
|
|
1,
|
|
&format!(
|
|
"debug/deps/{}pm-*.{}",
|
|
paths::get_lib_prefix("proc-macro"),
|
|
paths::get_lib_extension("proc-macro")
|
|
),
|
|
),
|
|
(1, "debug/deps/libbar-*.rlib"),
|
|
(1, "debug/deps/libregdep-*.rlib"),
|
|
],
|
|
);
|
|
|
|
assert_deps_contains(
|
|
&p,
|
|
"target/debug/.fingerprint/foo-*/dep-build-script-build-script-build",
|
|
&[(0, "build.rs"), (1, "debug/deps/libbdep-*.rlib")],
|
|
);
|
|
|
|
// Make sure it stays fresh.
|
|
p.cargo("build -Z binary-dep-depinfo")
|
|
.masquerade_as_nightly_cargo()
|
|
.with_stderr("[FINISHED] dev [..]")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn reg_dep_source_not_tracked() {
|
|
// Make sure source files in dep-info file are not tracked for registry dependencies.
|
|
Package::new("regdep", "0.1.0")
|
|
.file("src/lib.rs", "pub fn f() {}")
|
|
.publish();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
|
|
[dependencies]
|
|
regdep = "0.1"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "pub fn f() { regdep::f(); }")
|
|
.build();
|
|
|
|
p.cargo("build").run();
|
|
|
|
assert_deps(
|
|
&p,
|
|
"target/debug/.fingerprint/regdep-*/dep-lib-regdep",
|
|
|info_path, entries| {
|
|
for (kind, path) in entries {
|
|
if *kind == 1 {
|
|
panic!(
|
|
"Did not expect package root relative path type: {:?} in {:?}",
|
|
path, info_path
|
|
);
|
|
}
|
|
}
|
|
},
|
|
);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn canonical_path() {
|
|
if !is_nightly() {
|
|
// -Z binary-dep-depinfo is unstable (https://github.com/rust-lang/rust/issues/63012)
|
|
return;
|
|
}
|
|
if !cargo_test_support::symlink_supported() {
|
|
return;
|
|
}
|
|
Package::new("regdep", "0.1.0")
|
|
.file("src/lib.rs", "pub fn f() {}")
|
|
.publish();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
|
|
[dependencies]
|
|
regdep = "0.1"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "pub fn f() { regdep::f(); }")
|
|
.build();
|
|
|
|
let real = p.root().join("real_target");
|
|
real.mkdir_p();
|
|
p.symlink(real, "target");
|
|
|
|
p.cargo("build -Z binary-dep-depinfo")
|
|
.masquerade_as_nightly_cargo()
|
|
.run();
|
|
|
|
assert_deps_contains(
|
|
&p,
|
|
"target/debug/.fingerprint/foo-*/dep-lib-foo",
|
|
&[(0, "src/lib.rs"), (1, "debug/deps/libregdep-*.rmeta")],
|
|
);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn non_local_build_script() {
|
|
// Non-local build script information is not included.
|
|
Package::new("bar", "1.0.0")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo:rerun-if-changed=build.rs");
|
|
}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.publish();
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
|
|
[dependencies]
|
|
bar = "1.0"
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.build();
|
|
|
|
p.cargo("build").run();
|
|
let contents = p.read_file("target/debug/foo.d");
|
|
assert_match_exact(
|
|
"[ROOT]/foo/target/debug/foo[EXE]: [ROOT]/foo/src/main.rs",
|
|
&contents,
|
|
);
|
|
}
|