summaryrefslogtreecommitdiffstats
path: root/src/tools/cargo/tests/testsuite/metabuild.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/cargo/tests/testsuite/metabuild.rs')
-rw-r--r--src/tools/cargo/tests/testsuite/metabuild.rs771
1 files changed, 771 insertions, 0 deletions
diff --git a/src/tools/cargo/tests/testsuite/metabuild.rs b/src/tools/cargo/tests/testsuite/metabuild.rs
new file mode 100644
index 000000000..022d0bff0
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/metabuild.rs
@@ -0,0 +1,771 @@
+//! Tests for the metabuild feature (declarative build scripts).
+
+use cargo_test_support::{
+ basic_lib_manifest, basic_manifest, is_coarse_mtime, project, registry::Package, rustc_host,
+ Project,
+};
+
+use std::str;
+
+#[cargo_test]
+fn metabuild_gated() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ metabuild = ["mb"]
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .build();
+
+ p.cargo("check")
+ .masquerade_as_nightly_cargo(&["metabuild"])
+ .with_status(101)
+ .with_stderr(
+ "\
+error: failed to parse manifest at `[..]`
+
+Caused by:
+ feature `metabuild` is required
+
+ The package requires the Cargo feature called `metabuild`, \
+ but that feature is not stabilized in this version of Cargo (1.[..]).
+ Consider adding `cargo-features = [\"metabuild\"]` to the top of Cargo.toml \
+ (above the [package] table) to tell Cargo you are opting in to use this unstable feature.
+ See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#metabuild \
+ for more information about the status of this feature.
+",
+ )
+ .run();
+}
+
+fn basic_project() -> Project {
+ project()
+ .file(
+ "Cargo.toml",
+ r#"
+ cargo-features = ["metabuild"]
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ metabuild = ["mb", "mb-other"]
+
+ [build-dependencies]
+ mb = {path="mb"}
+ mb-other = {path="mb-other"}
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .file("mb/Cargo.toml", &basic_lib_manifest("mb"))
+ .file(
+ "mb/src/lib.rs",
+ r#"pub fn metabuild() { println!("Hello mb"); }"#,
+ )
+ .file(
+ "mb-other/Cargo.toml",
+ r#"
+ [package]
+ name = "mb-other"
+ version = "0.0.1"
+ "#,
+ )
+ .file(
+ "mb-other/src/lib.rs",
+ r#"pub fn metabuild() { println!("Hello mb-other"); }"#,
+ )
+ .build()
+}
+
+#[cargo_test]
+fn metabuild_basic() {
+ let p = basic_project();
+ p.cargo("check -vv")
+ .masquerade_as_nightly_cargo(&["metabuild"])
+ .with_stdout_contains("[foo 0.0.1] Hello mb")
+ .with_stdout_contains("[foo 0.0.1] Hello mb-other")
+ .run();
+}
+
+#[cargo_test]
+fn metabuild_error_both() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ cargo-features = ["metabuild"]
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ metabuild = "mb"
+
+ [build-dependencies]
+ mb = {path="mb"}
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .file("build.rs", r#"fn main() {}"#)
+ .file("mb/Cargo.toml", &basic_lib_manifest("mb"))
+ .file(
+ "mb/src/lib.rs",
+ r#"pub fn metabuild() { println!("Hello mb"); }"#,
+ )
+ .build();
+
+ p.cargo("check -vv")
+ .masquerade_as_nightly_cargo(&["metabuild"])
+ .with_status(101)
+ .with_stderr_contains(
+ "\
+error: failed to parse manifest at [..]
+
+Caused by:
+ cannot specify both `metabuild` and `build`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn metabuild_missing_dep() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ cargo-features = ["metabuild"]
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ metabuild = "mb"
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .build();
+
+ p.cargo("check -vv")
+ .masquerade_as_nightly_cargo(&["metabuild"])
+ .with_status(101)
+ .with_stderr_contains(
+ "\
+error: failed to parse manifest at [..]
+
+Caused by:
+ metabuild package `mb` must be specified in `build-dependencies`",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn metabuild_optional_dep() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ cargo-features = ["metabuild"]
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ metabuild = "mb"
+
+ [build-dependencies]
+ mb = {path="mb", optional=true}
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .file("mb/Cargo.toml", &basic_lib_manifest("mb"))
+ .file(
+ "mb/src/lib.rs",
+ r#"pub fn metabuild() { println!("Hello mb"); }"#,
+ )
+ .build();
+
+ p.cargo("check -vv")
+ .masquerade_as_nightly_cargo(&["metabuild"])
+ .with_stdout_does_not_contain("[foo 0.0.1] Hello mb")
+ .run();
+
+ p.cargo("check -vv --features mb")
+ .masquerade_as_nightly_cargo(&["metabuild"])
+ .with_stdout_contains("[foo 0.0.1] Hello mb")
+ .run();
+}
+
+#[cargo_test]
+fn metabuild_lib_name() {
+ // Test when setting `name` on [lib].
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ cargo-features = ["metabuild"]
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ metabuild = "mb"
+
+ [build-dependencies]
+ mb = {path="mb"}
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .file(
+ "mb/Cargo.toml",
+ r#"
+ [package]
+ name = "mb"
+ version = "0.0.1"
+ [lib]
+ name = "other"
+ "#,
+ )
+ .file(
+ "mb/src/lib.rs",
+ r#"pub fn metabuild() { println!("Hello mb"); }"#,
+ )
+ .build();
+
+ p.cargo("check -vv")
+ .masquerade_as_nightly_cargo(&["metabuild"])
+ .with_stdout_contains("[foo 0.0.1] Hello mb")
+ .run();
+}
+
+#[cargo_test]
+fn metabuild_fresh() {
+ if is_coarse_mtime() {
+ // This test doesn't work on coarse mtimes very well. Because the
+ // metabuild script is created at build time, its mtime is almost
+ // always equal to the mtime of the output. The second call to `build`
+ // will then think it needs to be rebuilt when it should be fresh.
+ return;
+ }
+
+ // Check that rebuild is fresh.
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ cargo-features = ["metabuild"]
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ metabuild = "mb"
+
+ [build-dependencies]
+ mb = {path="mb"}
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .file("mb/Cargo.toml", &basic_lib_manifest("mb"))
+ .file(
+ "mb/src/lib.rs",
+ r#"pub fn metabuild() { println!("Hello mb"); }"#,
+ )
+ .build();
+
+ p.cargo("check -vv")
+ .masquerade_as_nightly_cargo(&["metabuild"])
+ .with_stdout_contains("[foo 0.0.1] Hello mb")
+ .run();
+
+ p.cargo("check -vv")
+ .masquerade_as_nightly_cargo(&["metabuild"])
+ .with_stdout_does_not_contain("[foo 0.0.1] Hello mb")
+ .with_stderr(
+ "\
+[FRESH] mb [..]
+[FRESH] foo [..]
+[FINISHED] dev [..]
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn metabuild_links() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ cargo-features = ["metabuild"]
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ links = "cat"
+ metabuild = "mb"
+
+ [build-dependencies]
+ mb = {path="mb"}
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .file("mb/Cargo.toml", &basic_lib_manifest("mb"))
+ .file(
+ "mb/src/lib.rs",
+ r#"
+ pub fn metabuild() {
+ assert_eq!(std::env::var("CARGO_MANIFEST_LINKS"),
+ Ok("cat".to_string()));
+ println!("Hello mb");
+ }
+ "#,
+ )
+ .build();
+
+ p.cargo("check -vv")
+ .masquerade_as_nightly_cargo(&["metabuild"])
+ .with_stdout_contains("[foo 0.0.1] Hello mb")
+ .run();
+}
+
+#[cargo_test]
+fn metabuild_override() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ cargo-features = ["metabuild"]
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ links = "cat"
+ metabuild = "mb"
+
+ [build-dependencies]
+ mb = {path="mb"}
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .file("mb/Cargo.toml", &basic_lib_manifest("mb"))
+ .file(
+ "mb/src/lib.rs",
+ r#"pub fn metabuild() { panic!("should not run"); }"#,
+ )
+ .file(
+ ".cargo/config",
+ &format!(
+ r#"
+ [target.{}.cat]
+ rustc-link-lib = ["a"]
+ "#,
+ rustc_host()
+ ),
+ )
+ .build();
+
+ p.cargo("check -vv")
+ .masquerade_as_nightly_cargo(&["metabuild"])
+ .run();
+}
+
+#[cargo_test]
+fn metabuild_workspace() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [workspace]
+ members = ["member1", "member2"]
+ "#,
+ )
+ .file(
+ "member1/Cargo.toml",
+ r#"
+ cargo-features = ["metabuild"]
+ [package]
+ name = "member1"
+ version = "0.0.1"
+ metabuild = ["mb1", "mb2"]
+
+ [build-dependencies]
+ mb1 = {path="../../mb1"}
+ mb2 = {path="../../mb2"}
+ "#,
+ )
+ .file("member1/src/lib.rs", "")
+ .file(
+ "member2/Cargo.toml",
+ r#"
+ cargo-features = ["metabuild"]
+ [package]
+ name = "member2"
+ version = "0.0.1"
+ metabuild = ["mb1"]
+
+ [build-dependencies]
+ mb1 = {path="../../mb1"}
+ "#,
+ )
+ .file("member2/src/lib.rs", "")
+ .build();
+
+ project()
+ .at("mb1")
+ .file("Cargo.toml", &basic_lib_manifest("mb1"))
+ .file(
+ "src/lib.rs",
+ r#"pub fn metabuild() { println!("Hello mb1 {}", std::env::var("CARGO_MANIFEST_DIR").unwrap()); }"#,
+ )
+ .build();
+
+ project()
+ .at("mb2")
+ .file("Cargo.toml", &basic_lib_manifest("mb2"))
+ .file(
+ "src/lib.rs",
+ r#"pub fn metabuild() { println!("Hello mb2 {}", std::env::var("CARGO_MANIFEST_DIR").unwrap()); }"#,
+ )
+ .build();
+
+ p.cargo("check -vv --workspace")
+ .masquerade_as_nightly_cargo(&["metabuild"])
+ .with_stdout_contains("[member1 0.0.1] Hello mb1 [..]member1")
+ .with_stdout_contains("[member1 0.0.1] Hello mb2 [..]member1")
+ .with_stdout_contains("[member2 0.0.1] Hello mb1 [..]member2")
+ .with_stdout_does_not_contain("[member2 0.0.1] Hello mb2 [..]member2")
+ .run();
+}
+
+#[cargo_test]
+fn metabuild_metadata() {
+ // The metabuild Target is filtered out of the `metadata` results.
+ let p = basic_project();
+
+ let meta = p
+ .cargo("metadata --format-version=1")
+ .masquerade_as_nightly_cargo(&["metabuild"])
+ .run_json();
+ let mb_info: Vec<&str> = meta["packages"]
+ .as_array()
+ .unwrap()
+ .iter()
+ .find(|p| p["name"].as_str().unwrap() == "foo")
+ .unwrap()["metabuild"]
+ .as_array()
+ .unwrap()
+ .iter()
+ .map(|s| s.as_str().unwrap())
+ .collect();
+ assert_eq!(mb_info, ["mb", "mb-other"]);
+}
+
+#[cargo_test]
+fn metabuild_build_plan() {
+ let p = basic_project();
+
+ p.cargo("build --build-plan -Zunstable-options")
+ .masquerade_as_nightly_cargo(&["metabuild", "build-plan"])
+ .with_json(
+ r#"
+ {
+ "invocations": [
+ {
+ "package_name": "mb",
+ "package_version": "0.5.0",
+ "target_kind": ["lib"],
+ "compile_mode": "build",
+ "kind": null,
+ "deps": [],
+ "outputs": [
+ "[..]/target/debug/deps/libmb-[..].rlib",
+ "[..]/target/debug/deps/libmb-[..].rmeta"
+ ],
+ "links": {},
+ "program": "rustc",
+ "args": "{...}",
+ "env": "{...}",
+ "cwd": "[..]"
+ },
+ {
+ "package_name": "mb-other",
+ "package_version": "0.0.1",
+ "target_kind": ["lib"],
+ "compile_mode": "build",
+ "kind": null,
+ "deps": [],
+ "outputs": [
+ "[..]/target/debug/deps/libmb_other-[..].rlib",
+ "[..]/target/debug/deps/libmb_other-[..].rmeta"
+ ],
+ "links": {},
+ "program": "rustc",
+ "args": "{...}",
+ "env": "{...}",
+ "cwd": "[..]"
+ },
+ {
+ "package_name": "foo",
+ "package_version": "0.0.1",
+ "target_kind": ["custom-build"],
+ "compile_mode": "build",
+ "kind": null,
+ "deps": [0, 1],
+ "outputs": "{...}",
+ "links": "{...}",
+ "program": "rustc",
+ "args": "{...}",
+ "env": "{...}",
+ "cwd": "[..]"
+ },
+ {
+ "package_name": "foo",
+ "package_version": "0.0.1",
+ "target_kind": ["custom-build"],
+ "compile_mode": "run-custom-build",
+ "kind": null,
+ "deps": [2],
+ "outputs": [],
+ "links": {},
+ "program": "[..]/foo/target/debug/build/foo-[..]/metabuild-foo",
+ "args": [],
+ "env": "{...}",
+ "cwd": "[..]"
+ },
+ {
+ "package_name": "foo",
+ "package_version": "0.0.1",
+ "target_kind": ["lib"],
+ "compile_mode": "build",
+ "kind": null,
+ "deps": [3],
+ "outputs": [
+ "[..]/foo/target/debug/deps/libfoo-[..].rlib",
+ "[..]/foo/target/debug/deps/libfoo-[..].rmeta"
+ ],
+ "links": "{...}",
+ "program": "rustc",
+ "args": "{...}",
+ "env": "{...}",
+ "cwd": "[..]"
+ }
+ ],
+ "inputs": [
+ "[..]/foo/Cargo.toml",
+ "[..]/foo/mb/Cargo.toml",
+ "[..]/foo/mb-other/Cargo.toml"
+ ]
+ }
+ "#,
+ )
+ .run();
+
+ assert_eq!(p.glob("target/.metabuild/metabuild-foo-*.rs").count(), 1);
+}
+
+#[cargo_test]
+fn metabuild_two_versions() {
+ // Two versions of a metabuild dep with the same name.
+ let p = project()
+ .at("ws")
+ .file(
+ "Cargo.toml",
+ r#"
+ [workspace]
+ members = ["member1", "member2"]
+ "#,
+ )
+ .file(
+ "member1/Cargo.toml",
+ r#"
+ cargo-features = ["metabuild"]
+ [package]
+ name = "member1"
+ version = "0.0.1"
+ metabuild = ["mb"]
+
+ [build-dependencies]
+ mb = {path="../../mb1"}
+ "#,
+ )
+ .file("member1/src/lib.rs", "")
+ .file(
+ "member2/Cargo.toml",
+ r#"
+ cargo-features = ["metabuild"]
+ [package]
+ name = "member2"
+ version = "0.0.1"
+ metabuild = ["mb"]
+
+ [build-dependencies]
+ mb = {path="../../mb2"}
+ "#,
+ )
+ .file("member2/src/lib.rs", "")
+ .build();
+
+ project().at("mb1")
+ .file("Cargo.toml", r#"
+ [package]
+ name = "mb"
+ version = "0.0.1"
+ "#)
+ .file(
+ "src/lib.rs",
+ r#"pub fn metabuild() { println!("Hello mb1 {}", std::env::var("CARGO_MANIFEST_DIR").unwrap()); }"#,
+ )
+ .build();
+
+ project().at("mb2")
+ .file("Cargo.toml", r#"
+ [package]
+ name = "mb"
+ version = "0.0.2"
+ "#)
+ .file(
+ "src/lib.rs",
+ r#"pub fn metabuild() { println!("Hello mb2 {}", std::env::var("CARGO_MANIFEST_DIR").unwrap()); }"#,
+ )
+ .build();
+
+ p.cargo("check -vv --workspace")
+ .masquerade_as_nightly_cargo(&["metabuild"])
+ .with_stdout_contains("[member1 0.0.1] Hello mb1 [..]member1")
+ .with_stdout_contains("[member2 0.0.1] Hello mb2 [..]member2")
+ .run();
+
+ assert_eq!(
+ p.glob("target/.metabuild/metabuild-member?-*.rs").count(),
+ 2
+ );
+}
+
+#[cargo_test]
+fn metabuild_external_dependency() {
+ Package::new("mb", "1.0.0")
+ .file("Cargo.toml", &basic_manifest("mb", "1.0.0"))
+ .file(
+ "src/lib.rs",
+ r#"pub fn metabuild() { println!("Hello mb"); }"#,
+ )
+ .publish();
+ Package::new("dep", "1.0.0")
+ .file(
+ "Cargo.toml",
+ r#"
+ cargo-features = ["metabuild"]
+ [package]
+ name = "dep"
+ version = "1.0.0"
+ metabuild = ["mb"]
+
+ [build-dependencies]
+ mb = "1.0"
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .build_dep("mb", "1.0.0")
+ .publish();
+
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ [dependencies]
+ dep = "1.0"
+ "#,
+ )
+ .file("src/lib.rs", "extern crate dep;")
+ .build();
+
+ p.cargo("check -vv")
+ .masquerade_as_nightly_cargo(&["metabuild"])
+ .with_stdout_contains("[dep 1.0.0] Hello mb")
+ .run();
+
+ assert_eq!(p.glob("target/.metabuild/metabuild-dep-*.rs").count(), 1);
+}
+
+#[cargo_test]
+fn metabuild_json_artifact() {
+ let p = basic_project();
+ p.cargo("check --message-format=json")
+ .masquerade_as_nightly_cargo(&["metabuild"])
+ .with_json_contains_unordered(
+ r#"
+ {
+ "executable": null,
+ "features": [],
+ "filenames": "{...}",
+ "fresh": false,
+ "package_id": "foo [..]",
+ "manifest_path": "[..]",
+ "profile": "{...}",
+ "reason": "compiler-artifact",
+ "target": {
+ "crate_types": [
+ "bin"
+ ],
+ "doc": false,
+ "doctest": false,
+ "edition": "2018",
+ "kind": [
+ "custom-build"
+ ],
+ "name": "metabuild-foo",
+ "src_path": "[..]/foo/target/.metabuild/metabuild-foo-[..].rs",
+ "test": false
+ }
+ }
+
+ {
+ "cfgs": [],
+ "env": [],
+ "linked_libs": [],
+ "linked_paths": [],
+ "package_id": "foo [..]",
+ "out_dir": "[..]",
+ "reason": "build-script-executed"
+ }
+ "#,
+ )
+ .run();
+}
+
+#[cargo_test]
+fn metabuild_failed_build_json() {
+ let p = basic_project();
+ // Modify the metabuild dep so that it fails to compile.
+ p.change_file("mb/src/lib.rs", "");
+ p.cargo("check --message-format=json")
+ .masquerade_as_nightly_cargo(&["metabuild"])
+ .with_status(101)
+ .with_json_contains_unordered(
+ r#"
+ {
+ "message": {
+ "children": "{...}",
+ "code": "{...}",
+ "level": "error",
+ "message": "cannot find function `metabuild` in [..] `mb`",
+ "rendered": "{...}",
+ "spans": "{...}"
+ },
+ "package_id": "foo [..]",
+ "manifest_path": "[..]",
+ "reason": "compiler-message",
+ "target": {
+ "crate_types": [
+ "bin"
+ ],
+ "doc": false,
+ "doctest": false,
+ "edition": "2018",
+ "kind": [
+ "custom-build"
+ ],
+ "name": "metabuild-foo",
+ "src_path": null,
+ "test": false
+ }
+ }
+ "#,
+ )
+ .run();
+}