//! Tests for profiles. use std::env; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::{project, rustc_host, str}; #[cargo_test] fn profile_overrides() { let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.0.0" edition = "2015" authors = [] [profile.dev] opt-level = 1 debug = false rpath = true "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v").with_stderr_data(str![[r#" [COMPILING] test v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name test --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link[..] -C opt-level=1[..] -C debug-assertions=on[..] -C metadata=[..] -C rpath --out-dir [ROOT]/foo/target/debug/deps [..] -L dependency=[ROOT]/foo/target/debug/deps` [FINISHED] `dev` profile [optimized] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn opt_level_override_0() { let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.0.0" edition = "2015" authors = [] [profile.dev] opt-level = 0 "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v").with_stderr_data(str![[r#" [COMPILING] test v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name test --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C debuginfo=2 [..] -C metadata=[..] --out-dir [ROOT]/foo/target/debug/deps -L dependency=[ROOT]/foo/target/debug/deps` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn debug_override_1() { let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.0.0" edition = "2015" authors = [] [profile.dev] debug = 1 "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v").with_stderr_data(str![[r#" [COMPILING] test v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name test --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C debuginfo=1 [..]-C metadata=[..] --out-dir [ROOT]/foo/target/debug/deps -L dependency=[ROOT]/foo/target/debug/deps` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } fn check_opt_level_override(profile_level: &str, rustc_level: &str) { let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "test" version = "0.0.0" edition = "2015" authors = [] [profile.dev] opt-level = {level} "#, level = profile_level ), ) .file("src/lib.rs", "") .build(); p.cargo("build -v") .with_stderr_data(&format!( "\ [COMPILING] test v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name test --edition=2015 src/lib.rs [..]--crate-type lib \ --emit=[..]link \ -C opt-level={level}[..]\ -C debuginfo=2 [..]\ -C debug-assertions=on[..] \ -C metadata=[..] \ --out-dir [..] \ -L dependency=[ROOT]/foo/target/debug/deps` [FINISHED] `dev` profile [..]+ debuginfo] target(s) in [ELAPSED]s ", level = rustc_level )) .run(); } #[cargo_test] fn opt_level_overrides() { for &(profile_level, rustc_level) in &[ ("1", "1"), ("2", "2"), ("3", "3"), ("\"s\"", "s"), ("\"z\"", "z"), ] { check_opt_level_override(profile_level, rustc_level) } } #[cargo_test] fn top_level_overrides_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.0.0" edition = "2015" authors = [] [profile.release] opt-level = 1 debug = true [dependencies.foo] path = "foo" "#, ) .file("src/lib.rs", "") .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [profile.release] opt-level = 0 debug = false [lib] name = "foo" crate-type = ["dylib", "rlib"] "#, ) .file("foo/src/lib.rs", "") .build(); p.cargo("build -v --release") .with_stderr_data(&format!( "\ [LOCKING] 2 packages to latest compatible versions [COMPILING] foo v0.0.0 ([ROOT]/foo/foo) [RUNNING] `rustc --crate-name foo --edition=2015 foo/src/lib.rs [..]\ --crate-type dylib --crate-type rlib \ --emit=[..]link \ -C prefer-dynamic \ -C opt-level=1[..]\ -C debuginfo=2 [..]\ -C metadata=[..] \ --out-dir [ROOT]/foo/target/release/deps \ -L dependency=[ROOT]/foo/target/release/deps` [COMPILING] test v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name test --edition=2015 src/lib.rs [..]--crate-type lib \ --emit=[..]link \ -C opt-level=1[..]\ -C debuginfo=2 [..]\ -C metadata=[..] \ --out-dir [..] \ -L dependency=[ROOT]/foo/target/release/deps \ --extern foo=[ROOT]/foo/target/release/deps/\ {prefix}foo[..]{suffix} \ --extern foo=[ROOT]/foo/target/release/deps/libfoo.rlib` [FINISHED] `release` profile [optimized + debuginfo] target(s) in [ELAPSED]s ", prefix = env::consts::DLL_PREFIX, suffix = env::consts::DLL_SUFFIX )) .run(); } #[cargo_test] fn profile_in_non_root_manifest_triggers_a_warning() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["bar"] [profile.dev] debug = false "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] workspace = ".." [profile.dev] opt-level = 1 "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("build -v") .cwd("bar") .with_stderr_data(str![[r#" [WARNING] profiles for the non root package will be ignored, specify profiles at the workspace root: package: [ROOT]/foo/bar/Cargo.toml workspace: [ROOT]/foo/Cargo.toml [LOCKING] 2 packages to latest compatible versions [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [RUNNING] `rustc [..]` [FINISHED] `dev` profile [unoptimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn profile_in_virtual_manifest_works() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] [profile.dev] opt-level = 1 debug = false "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] workspace = ".." "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("build -v") .cwd("bar") .with_stderr_data(str![[r#" [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [RUNNING] `rustc [..]` [FINISHED] `dev` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn profile_lto_string_bool_dev() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [profile.dev] lto = "true" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `lto` setting of string `"true"` for `dev` profile is not a valid setting, must be a boolean (`true`/`false`) or a string (`"thin"`/`"fat"`/`"off"`) or omitted. "#]]) .run(); } #[cargo_test] fn profile_panic_test_bench() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [profile.test] panic = "abort" [profile.bench] panic = "abort" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_stderr_data(str![[r#" [WARNING] `panic` setting is ignored for `bench` profile [WARNING] `panic` setting is ignored for `test` profile [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn profile_doc_deprecated() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [profile.doc] opt-level = 0 "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_stderr_data(str![[r#" [WARNING] profile `doc` is deprecated and has no effect ... "#]]) .run(); } #[cargo_test] fn panic_unwind_does_not_build_twice() { // Check for a bug where `lib` was built twice, once with panic set and // once without. Since "unwind" is the default, they are the same and // should only be built once. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.dev] panic = "unwind" "#, ) .file("src/lib.rs", "") .file("src/main.rs", "fn main() {}") .file("tests/t1.rs", "") .build(); p.cargo("test -v --tests --no-run") .with_stderr_data( str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib [..]` [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..] --test [..]` [RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin [..]` [RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..] --test [..]` [RUNNING] `rustc --crate-name t1 --edition=2015 tests/t1.rs [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [EXECUTABLE] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` [EXECUTABLE] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` [EXECUTABLE] `[ROOT]/foo/target/debug/deps/t1-[HASH][EXE]` "#]] .unordered(), ) .run(); } #[allow(deprecated)] #[cargo_test] fn debug_0_report() { // The finished line handles 0 correctly. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.dev] debug = 0 "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]` [FINISHED] `dev` profile [unoptimized] target(s) in [ELAPSED]s "#]]) .with_stderr_does_not_contain("-C debuginfo") .run(); } #[cargo_test] fn thin_lto_works() { let p = project() .file( "Cargo.toml", r#" [package] name = "top" version = "0.5.0" edition = "2015" authors = [] [profile.release] lto = 'thin' "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build --release -v") .with_stderr_data(str![[r#" [COMPILING] top v0.5.0 ([ROOT]/foo) [RUNNING] `rustc [..] -C lto=thin [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn strip_works() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.release] strip = 'symbols' "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build --release -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] -C strip=symbols [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn strip_passes_unknown_option_to_rustc() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.release] strip = 'unknown' "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build --release -v") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] -C strip=unknown [..]` [ERROR] incorrect value `unknown` for [..] `strip` [..] was expected ... "#]]) .run(); } #[cargo_test] fn strip_accepts_true_to_strip_symbols() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.release] strip = true "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build --release -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] -C strip=symbols [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[allow(deprecated)] #[cargo_test] fn strip_accepts_false_to_disable_strip() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.release] strip = false "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build --release -v") .with_stderr_does_not_contain("[RUNNING] `rustc [..] -C strip[..]`") .run(); } #[cargo_test] fn strip_debuginfo_in_release() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build --release -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] -C strip=debuginfo[..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build --release -v --target") .arg(rustc_host()) .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] -C strip=debuginfo[..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn strip_debuginfo_without_debug() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.dev] debug = 0 "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -C strip=debuginfo[..]` [FINISHED] `dev` profile [unoptimized] target(s) in [ELAPSED]s "#]]) .run(); } #[allow(deprecated)] #[cargo_test] fn do_not_strip_debuginfo_with_requested_debug() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar" } [profile.release.package.bar] debug = 1 "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("build --release -v") .with_stderr_does_not_contain("[RUNNING] `rustc [..] -C strip=debuginfo[..]`") .run(); } #[cargo_test] fn rustflags_works() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["profile-rustflags"] [profile.dev] rustflags = ["-C", "link-dead-code=yes"] [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -v") .masquerade_as_nightly_cargo(&["profile-rustflags"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -C link-dead-code=yes [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rustflags_works_with_env() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["profile-rustflags"] [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -v") .env("CARGO_PROFILE_DEV_RUSTFLAGS", "-C link-dead-code=yes") .masquerade_as_nightly_cargo(&["profile-rustflags"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -C link-dead-code=yes [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rustflags_requires_cargo_feature() { let p = project() .file( "Cargo.toml", r#" [profile.dev] rustflags = ["-C", "link-dead-code=yes"] [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -v") .masquerade_as_nightly_cargo(&["profile-rustflags"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `profile-rustflags` is required The package requires the Cargo feature called `profile-rustflags`, but that feature is not stabilized in this version of Cargo (1.[..]). Consider adding `cargo-features = ["profile-rustflags"]` 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#profile-rustflags-option for more information about the status of this feature. "#]]) .run(); Package::new("bar", "1.0.0").publish(); p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = "1.0" [profile.dev.package.bar] rustflags = ["-C", "link-dead-code=yes"] "#, ); p.cargo("check") .masquerade_as_nightly_cargo(&["profile-rustflags"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `profile-rustflags` is required The package requires the Cargo feature called `profile-rustflags`, but that feature is not stabilized in this version of Cargo (1.[..]). Consider adding `cargo-features = ["profile-rustflags"]` 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#profile-rustflags-option for more information about the status of this feature. "#]]) .run(); } #[allow(deprecated)] #[cargo_test] fn debug_options_valid() { let build = |option| { let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" authors = [] version = "0.0.0" edition = "2015" [profile.dev] debug = "{option}" "# ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -v") }; for (option, cli) in [ ("line-directives-only", "line-directives-only"), ("line-tables-only", "line-tables-only"), ("limited", "1"), ("full", "2"), ] { build(option) .with_stderr_data(&format!( "\ ... [RUNNING] `rustc [..]-C debuginfo={cli} [..]` ... " )) .run(); } build("none") .with_stderr_does_not_contain("[..]-C debuginfo[..]") .run(); }