cargo/tests/testsuite/lto.rs

846 lines
24 KiB
Rust
Raw Normal View History

2020-06-10 22:31:36 +00:00
use cargo::core::compiler::Lto;
Add support for `-Cembed-bitcode=no` This commit is the Cargo half of support necessary for rust-lang/rust#70458. Today the compiler emits embedded bytecode in rlibs by default, but compresses it. This is both extraneous disk space and wasted build time for almost all builds, so the PR in question there is changing rustc to have a `-Cembed-bitcode` flag which, when enabled, places the bitcode in the object file rather than an auxiliary file (no extra compression), but also enables `-Cembed-bitcode=no` to disable bitcode emission entirely. This Cargo support changes Cargo to pass `-Cembed-bitcode=no` for almost all compilations. Cargo will keep `lto = true` and such working by not passing this flag (and thus allowing bitcode to get embedded), but by default `cargo build` and `cargo build --release` will no longer have any bitcode in rlibs which should result in speedier builds! Most of the changes here were around the test suite and various assertions about the `rustc` command lines we spit out. One test was hard-disabled until we can get `-Cembed-bitcode=no` into nightly, and then we can make it a nightly-only test. The test will then be stable again once `-Cembed-bitcode=no` hits stable. Note that this is intended to land before the upstream `-Cembed-bitcode` change. The thinking is that we'll land everything in rust-lang/rust all at once so there's no build time regressions for anyone. If we were to land the `-Cembed-bitcode` PR first then there would be a build time regression until we land Cargo changes because rustc would be emitting uncompressed bitcode by default and Cargo wouldn't be turning it off.
2020-04-01 18:41:27 +00:00
use cargo_test_support::registry::Package;
2020-08-27 23:41:43 +00:00
use cargo_test_support::{basic_manifest, project, Project};
2020-06-10 22:31:36 +00:00
use std::process::Output;
Add support for `-Cembed-bitcode=no` This commit is the Cargo half of support necessary for rust-lang/rust#70458. Today the compiler emits embedded bytecode in rlibs by default, but compresses it. This is both extraneous disk space and wasted build time for almost all builds, so the PR in question there is changing rustc to have a `-Cembed-bitcode` flag which, when enabled, places the bitcode in the object file rather than an auxiliary file (no extra compression), but also enables `-Cembed-bitcode=no` to disable bitcode emission entirely. This Cargo support changes Cargo to pass `-Cembed-bitcode=no` for almost all compilations. Cargo will keep `lto = true` and such working by not passing this flag (and thus allowing bitcode to get embedded), but by default `cargo build` and `cargo build --release` will no longer have any bitcode in rlibs which should result in speedier builds! Most of the changes here were around the test suite and various assertions about the `rustc` command lines we spit out. One test was hard-disabled until we can get `-Cembed-bitcode=no` into nightly, and then we can make it a nightly-only test. The test will then be stable again once `-Cembed-bitcode=no` hits stable. Note that this is intended to land before the upstream `-Cembed-bitcode` change. The thinking is that we'll land everything in rust-lang/rust all at once so there's no build time regressions for anyone. If we were to land the `-Cembed-bitcode` PR first then there would be a build time regression until we land Cargo changes because rustc would be emitting uncompressed bitcode by default and Cargo wouldn't be turning it off.
2020-04-01 18:41:27 +00:00
#[cargo_test]
fn with_deps() {
Package::new("bar", "0.0.1").publish();
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "test"
version = "0.0.0"
[dependencies]
bar = "*"
[profile.release]
lto = true
"#,
)
.file("src/main.rs", "extern crate bar; fn main() {}")
.build();
p.cargo("build -v --release")
.with_stderr_contains("[..]`rustc[..]--crate-name bar[..]-C linker-plugin-lto[..]`")
.with_stderr_contains("[..]`rustc[..]--crate-name test[..]-C lto[..]`")
.run();
}
#[cargo_test]
fn shared_deps() {
Package::new("bar", "0.0.1").publish();
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "test"
version = "0.0.0"
[dependencies]
bar = "*"
[build-dependencies]
bar = "*"
[profile.release]
lto = true
"#,
)
.file("build.rs", "extern crate bar; fn main() {}")
.file("src/main.rs", "extern crate bar; fn main() {}")
.build();
p.cargo("build -v --release")
.with_stderr_contains("[..]`rustc[..]--crate-name test[..]-C lto[..]`")
.run();
}
#[cargo_test]
fn build_dep_not_ltod() {
Package::new("bar", "0.0.1").publish();
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "test"
version = "0.0.0"
[build-dependencies]
bar = "*"
[profile.release]
lto = true
"#,
)
.file("build.rs", "extern crate bar; fn main() {}")
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("build -v --release")
.with_stderr_contains("[..]`rustc[..]--crate-name bar[..]-C embed-bitcode=no[..]`")
.with_stderr_contains("[..]`rustc[..]--crate-name test[..]-C lto[..]`")
.run();
}
#[cargo_test]
fn complicated() {
Package::new("dep-shared", "0.0.1")
.file("src/lib.rs", "pub fn foo() {}")
.publish();
Package::new("dep-normal2", "0.0.1")
.file("src/lib.rs", "pub fn foo() {}")
.publish();
Package::new("dep-normal", "0.0.1")
.dep("dep-shared", "*")
.dep("dep-normal2", "*")
.file(
"src/lib.rs",
"
pub fn foo() {
dep_shared::foo();
dep_normal2::foo();
}
",
)
.publish();
Package::new("dep-build2", "0.0.1")
.file("src/lib.rs", "pub fn foo() {}")
.publish();
Package::new("dep-build", "0.0.1")
.dep("dep-shared", "*")
.dep("dep-build2", "*")
.file(
"src/lib.rs",
"
pub fn foo() {
dep_shared::foo();
dep_build2::foo();
}
",
)
.publish();
Package::new("dep-proc-macro2", "0.0.1")
.file("src/lib.rs", "pub fn foo() {}")
.publish();
Package::new("dep-proc-macro", "0.0.1")
.proc_macro(true)
.dep("dep-shared", "*")
.dep("dep-proc-macro2", "*")
.file(
"src/lib.rs",
"
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_attribute]
pub fn foo(_: TokenStream, a: TokenStream) -> TokenStream {
dep_shared::foo();
dep_proc_macro2::foo();
a
}
",
)
.publish();
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "test"
version = "0.0.0"
[lib]
crate-type = ['cdylib', 'staticlib']
[dependencies]
dep-normal = "*"
dep-proc-macro = "*"
[build-dependencies]
dep-build = "*"
[profile.release]
lto = true
Build host dependencies with opt-level 0 by default This commit updates Cargo's build of host dependencies to build them with optimization level 0 by default instead of matching the profile of the final binary. Since Cargo's inception build dependencies have, by default, been built in a profile that largely matches the profile of the final target artifact. Build dependencies, however, rarely actually need to be optimized and are often executing very small tasks, which means that optimizing them often wastes a lot of build time. A great example of this is procedural macros where `syn` and friends are pretty heavyweight to optimize, and the amount of Rust code they're parsing is typically quite small, so the time spent optimizing rarely comes as a benefit. The goal of this PR is to improve build times on average in the community by not spending time optimizing build dependencies (build scripts, procedural macros, and their transitive dependencies). The PR will not be a universal win for everyone, however. There's some situations where your build time may actually increase: * In some cases build scripts and procedural macros can take quite a long time to run! * Cargo may not build dependencies more than once if they're shared with the main build. This only applies to builds without `--target` where the same crate is used in the final binary as in a build script. In these cases, however, the `build-override` profile has existed for some time know and allows giving a knob to tweak this behavior. For example to get back the previous build behavior of Cargo you would specify, in `Cargo.toml`: [profile.release.build-override] opt-level = 3 or you can configure this via the environment: export CARGO_PROFILE_RELEASE_BUILD_OVERRIDE_OPT_LEVEL=3 There are two notable features we would like to add in the future which would make the impact of a change like this smaller, but they're not implemented at this time (nor do we have concrete plans to implement them). First we would like crates to have a way of specifying they should be optimized by default, despite default profile options. Often crates, like lalrpop historically, have abysmal performance in debug mode and almost always (even in debug builds) want to be built in release mode. The second feature is that ideally crate authors would be able to tell Cargo to minimize the number of crates built, unifying profiles where possible to avoid double-compiling crates. At this time though the Cargo team feels that the benefit of changing the defaults is well worth this change. Neither today nor directly after this change will be a perfect world, but it's hoped that this change makes things less bad!
2020-07-17 19:39:41 +00:00
# force build deps to share an opt-level with the rest of the
# graph so they only get built once.
[profile.release.build-override]
opt-level = 3
"#,
)
.file("build.rs", "fn main() { dep_build::foo() }")
.file(
2021-11-29 18:04:15 +00:00
"src/bin/foo-bin.rs",
"#[dep_proc_macro::foo] fn main() { dep_normal::foo() }",
)
.file(
"src/lib.rs",
"#[dep_proc_macro::foo] pub fn foo() { dep_normal::foo() }",
)
.build();
p.cargo("build -v --release")
// normal deps and their transitive dependencies do not need object
// code, so they should have linker-plugin-lto specified
.with_stderr_contains(
"[..]`rustc[..]--crate-name dep_normal2 [..]-C linker-plugin-lto[..]`",
)
.with_stderr_contains("[..]`rustc[..]--crate-name dep_normal [..]-C linker-plugin-lto[..]`")
// build dependencies and their transitive deps don't need any bitcode,
// so embedding should be turned off
.with_stderr_contains("[..]`rustc[..]--crate-name dep_build2 [..]-C embed-bitcode=no[..]`")
.with_stderr_contains("[..]`rustc[..]--crate-name dep_build [..]-C embed-bitcode=no[..]`")
.with_stderr_contains(
"[..]`rustc[..]--crate-name build_script_build [..]-C embed-bitcode=no[..]`",
)
// proc macro deps are the same as build deps here
.with_stderr_contains(
"[..]`rustc[..]--crate-name dep_proc_macro2 [..]-C embed-bitcode=no[..]`",
)
.with_stderr_contains(
"[..]`rustc[..]--crate-name dep_proc_macro [..]-C embed-bitcode=no[..]`",
)
2021-11-29 18:04:15 +00:00
.with_stderr_contains(
"[..]`rustc[..]--crate-name foo_bin [..]--crate-type bin[..]-C lto[..]`",
)
.with_stderr_contains(
"[..]`rustc[..]--crate-name test [..]--crate-type cdylib[..]-C lto[..]`",
)
.with_stderr_contains("[..]`rustc[..]--crate-name dep_shared [..]`")
.with_stderr_does_not_contain("[..]--crate-name dep_shared[..]-C lto[..]")
.with_stderr_does_not_contain("[..]--crate-name dep_shared[..]-C linker-plugin-lto[..]")
.with_stderr_does_not_contain("[..]--crate-name dep_shared[..]-C embed-bitcode[..]")
.run();
}
#[cargo_test]
fn off_in_manifest_works() {
Package::new("bar", "0.0.1")
.file("src/lib.rs", "pub fn foo() {}")
.publish();
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "test"
version = "0.0.0"
[dependencies]
bar = "*"
[profile.release]
lto = "off"
"#,
)
2020-06-10 22:31:36 +00:00
.file("src/lib.rs", "pub fn foo() {}")
.file(
"src/main.rs",
"fn main() {
test::foo();
bar::foo();
}",
)
.build();
2020-06-10 22:31:36 +00:00
p.cargo("build -v --release")
.with_stderr(
"\
[UPDATING] [..]
[DOWNLOADING] [..]
[DOWNLOADED] [..]
[COMPILING] bar v0.0.1
[RUNNING] `rustc --crate-name bar [..]--crate-type lib [..]-C lto=off -C embed-bitcode=no[..]
2020-06-10 22:31:36 +00:00
[COMPILING] test [..]
[RUNNING] `rustc --crate-name test [..]--crate-type lib [..]-C lto=off -C embed-bitcode=no[..]
2020-06-10 22:31:36 +00:00
[RUNNING] `rustc --crate-name test src/main.rs [..]--crate-type bin [..]-C lto=off[..]
[FINISHED] [..]
",
)
.run();
}
#[cargo_test]
fn between_builds() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "test"
version = "0.0.0"
[profile.release]
lto = true
"#,
)
.file("src/lib.rs", "pub fn foo() {}")
.file("src/main.rs", "fn main() { test::foo() }")
.build();
2020-06-10 22:31:36 +00:00
p.cargo("build -v --release --lib")
.with_stderr(
"\
[COMPILING] test [..]
[RUNNING] `rustc [..]--crate-type lib[..]-C linker-plugin-lto[..]
2020-06-10 22:31:36 +00:00
[FINISHED] [..]
",
)
.run();
p.cargo("build -v --release")
.with_stderr_contains(
"\
[COMPILING] test [..]
[RUNNING] `rustc [..]--crate-type bin[..]-C lto[..]
[FINISHED] [..]
",
)
.run();
Add support for `-Cembed-bitcode=no` This commit is the Cargo half of support necessary for rust-lang/rust#70458. Today the compiler emits embedded bytecode in rlibs by default, but compresses it. This is both extraneous disk space and wasted build time for almost all builds, so the PR in question there is changing rustc to have a `-Cembed-bitcode` flag which, when enabled, places the bitcode in the object file rather than an auxiliary file (no extra compression), but also enables `-Cembed-bitcode=no` to disable bitcode emission entirely. This Cargo support changes Cargo to pass `-Cembed-bitcode=no` for almost all compilations. Cargo will keep `lto = true` and such working by not passing this flag (and thus allowing bitcode to get embedded), but by default `cargo build` and `cargo build --release` will no longer have any bitcode in rlibs which should result in speedier builds! Most of the changes here were around the test suite and various assertions about the `rustc` command lines we spit out. One test was hard-disabled until we can get `-Cembed-bitcode=no` into nightly, and then we can make it a nightly-only test. The test will then be stable again once `-Cembed-bitcode=no` hits stable. Note that this is intended to land before the upstream `-Cembed-bitcode` change. The thinking is that we'll land everything in rust-lang/rust all at once so there's no build time regressions for anyone. If we were to land the `-Cembed-bitcode` PR first then there would be a build time regression until we land Cargo changes because rustc would be emitting uncompressed bitcode by default and Cargo wouldn't be turning it off.
2020-04-01 18:41:27 +00:00
}
#[cargo_test]
fn test_all() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.0"
[profile.release]
lto = true
"#,
)
.file("src/main.rs", "fn main() {}")
.file("tests/a.rs", "")
.file("tests/b.rs", "")
.build();
p.cargo("test --release -v")
.with_stderr_contains("[RUNNING] `rustc[..]--crate-name foo[..]-C lto[..]")
.run();
}
#[cargo_test]
fn test_all_and_bench() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.0"
[profile.release]
lto = true
[profile.bench]
lto = true
"#,
)
.file("src/main.rs", "fn main() {}")
.file("tests/a.rs", "")
.file("tests/b.rs", "")
.build();
p.cargo("test --release -v")
.with_stderr_contains("[RUNNING] `rustc[..]--crate-name a[..]-C lto[..]")
.with_stderr_contains("[RUNNING] `rustc[..]--crate-name b[..]-C lto[..]")
.with_stderr_contains("[RUNNING] `rustc[..]--crate-name foo[..]-C lto[..]")
.run();
}
2021-09-24 04:55:42 +00:00
/// Basic setup:
///
/// foo v0.0.0
/// ├── bar v0.0.0
/// │ ├── registry v0.0.1
/// │ └── registry-shared v0.0.1
/// └── registry-shared v0.0.1
///
/// Where `bar` will have the given crate types.
2020-06-10 22:31:36 +00:00
fn project_with_dep(crate_types: &str) -> Project {
Package::new("registry", "0.0.1")
2020-06-10 22:31:36 +00:00
.file("src/lib.rs", r#"pub fn foo() { println!("registry"); }"#)
.publish();
Package::new("registry-shared", "0.0.1")
2020-06-10 22:31:36 +00:00
.file("src/lib.rs", r#"pub fn foo() { println!("shared"); }"#)
.publish();
2020-06-10 22:31:36 +00:00
project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.0"
[workspace]
[dependencies]
bar = { path = 'bar' }
registry-shared = "*"
[profile.release]
lto = true
"#,
)
.file(
"src/main.rs",
"
fn main() {
bar::foo();
registry_shared::foo();
}
",
)
.file(
"bar/Cargo.toml",
2020-06-10 22:31:36 +00:00
&format!(
r#"
2020-09-27 00:59:58 +00:00
[package]
name = "bar"
version = "0.0.0"
2020-09-27 00:59:58 +00:00
[dependencies]
registry = "*"
registry-shared = "*"
2020-09-27 00:59:58 +00:00
[lib]
crate-type = [{}]
"#,
2020-06-10 22:31:36 +00:00
crate_types
),
)
.file(
"bar/src/lib.rs",
2020-06-10 22:31:36 +00:00
r#"
pub fn foo() {
2020-06-10 22:31:36 +00:00
println!("bar");
registry::foo();
registry_shared::foo();
}
2020-06-10 22:31:36 +00:00
"#,
)
.file("tests/a.rs", "")
.file("bar/tests/b.rs", "")
2020-06-10 22:31:36 +00:00
.build()
}
2021-09-24 04:55:42 +00:00
/// Helper for checking which LTO behavior is used for a specific crate.
///
/// `krate_info` is extra compiler flags used to distinguish this if the same
/// crate name is being built multiple times.
2020-06-10 22:31:36 +00:00
fn verify_lto(output: &Output, krate: &str, krate_info: &str, expected_lto: Lto) {
let stderr = std::str::from_utf8(&output.stderr).unwrap();
let mut matches = stderr.lines().filter(|line| {
line.contains("Running")
&& line.contains(&format!("--crate-name {} ", krate))
&& line.contains(krate_info)
});
let line = matches.next().unwrap_or_else(|| {
panic!(
"expected to find crate `{}` info: `{}`, not found in output:\n{}",
krate, krate_info, stderr
);
});
if let Some(line2) = matches.next() {
panic!(
"found multiple lines matching crate `{}` info: `{}`:\nline1:{}\nline2:{}\noutput:\n{}",
krate, krate_info, line, line2, stderr
);
}
let actual_lto = if let Some(index) = line.find("-C lto=") {
let s = &line[index..];
let end = s.find(' ').unwrap();
let mode = &line[index..index + end];
if mode == "off" {
Lto::Off
} else {
Lto::Run(Some(mode.into()))
}
} else if line.contains("-C lto") {
Lto::Run(None)
} else if line.contains("-C linker-plugin-lto") {
2020-06-10 22:31:36 +00:00
Lto::OnlyBitcode
} else if line.contains("-C embed-bitcode=no") {
2020-06-10 22:31:36 +00:00
Lto::OnlyObject
} else {
Lto::ObjectAndBitcode
};
assert_eq!(
actual_lto, expected_lto,
"did not find expected LTO in line: {}",
line
);
}
#[cargo_test]
fn cdylib_and_rlib() {
let p = project_with_dep("'cdylib', 'rlib'");
let output = p.cargo("build --release -v").exec_with_output().unwrap();
2022-10-26 04:15:45 +00:00
// `registry` is ObjectAndBitcode because it needs Object for the
2021-09-24 04:55:42 +00:00
// rlib, and Bitcode for the cdylib (which doesn't support LTO).
2020-06-10 22:31:36 +00:00
verify_lto(
&output,
"registry",
"--crate-type lib",
Lto::ObjectAndBitcode,
);
2021-09-24 04:55:42 +00:00
// Same as `registry`
2020-06-10 22:31:36 +00:00
verify_lto(
&output,
"registry_shared",
"--crate-type lib",
Lto::ObjectAndBitcode,
);
2021-09-24 04:55:42 +00:00
// Same as `registry`
2020-06-10 22:31:36 +00:00
verify_lto(
&output,
"bar",
"--crate-type cdylib --crate-type rlib",
Lto::ObjectAndBitcode,
);
verify_lto(&output, "foo", "--crate-type bin", Lto::Run(None));
p.cargo("test --release -v")
.with_stderr_unordered(
"\
[FRESH] registry v0.0.1
[FRESH] registry-shared v0.0.1
[FRESH] bar v0.0.0 [..]
[COMPILING] foo [..]
2021-09-24 04:55:42 +00:00
[RUNNING] `rustc --crate-name foo [..]-C lto [..]--test[..]
[RUNNING] `rustc --crate-name a [..]-C lto [..]--test[..]
2020-06-10 22:31:36 +00:00
[FINISHED] [..]
[RUNNING] [..]
[RUNNING] [..]
",
)
.run();
p.cargo("build --release -v --manifest-path bar/Cargo.toml")
2020-06-10 22:31:36 +00:00
.with_stderr_unordered(
"\
[FRESH] registry-shared v0.0.1
[FRESH] registry v0.0.1
[FRESH] bar v0.0.0 [..]
[FINISHED] [..]
",
)
.run();
p.cargo("test --release -v --manifest-path bar/Cargo.toml")
2020-06-10 22:31:36 +00:00
.with_stderr_unordered(
"\
2021-09-24 04:55:42 +00:00
[FRESH] registry-shared v0.0.1
[FRESH] registry v0.0.1
2020-06-10 22:31:36 +00:00
[COMPILING] bar [..]
2021-09-24 04:55:42 +00:00
[RUNNING] `rustc --crate-name bar [..]-C lto[..]--test[..]
[RUNNING] `rustc --crate-name b [..]-C lto[..]--test[..]
2020-06-10 22:31:36 +00:00
[FINISHED] [..]
2020-08-27 23:41:43 +00:00
[RUNNING] [..]target/release/deps/bar-[..]
[RUNNING] [..]target/release/deps/b-[..]
2020-06-10 22:31:36 +00:00
[DOCTEST] bar
2021-09-24 04:55:42 +00:00
[RUNNING] `rustdoc --crate-type cdylib --crate-type rlib --crate-name bar --test [..]-C lto[..]
2020-06-10 22:31:36 +00:00
",
)
.run();
}
#[cargo_test]
fn dylib() {
let p = project_with_dep("'dylib'");
let output = p.cargo("build --release -v").exec_with_output().unwrap();
2021-09-24 04:55:42 +00:00
// `registry` is OnlyObject because rustc doesn't support LTO with dylibs.
2020-06-10 22:31:36 +00:00
verify_lto(&output, "registry", "--crate-type lib", Lto::OnlyObject);
2021-09-24 04:55:42 +00:00
// `registry_shared` is both because it is needed by both bar (Object) and
// foo (Bitcode for LTO).
2020-06-10 22:31:36 +00:00
verify_lto(
&output,
"registry_shared",
"--crate-type lib",
Lto::ObjectAndBitcode,
);
2021-09-24 04:55:42 +00:00
// `bar` is OnlyObject because rustc doesn't support LTO with dylibs.
2020-06-10 22:31:36 +00:00
verify_lto(&output, "bar", "--crate-type dylib", Lto::OnlyObject);
2021-09-24 04:55:42 +00:00
// `foo` is LTO because it is a binary, and the profile specifies `lto=true`.
2020-06-10 22:31:36 +00:00
verify_lto(&output, "foo", "--crate-type bin", Lto::Run(None));
2021-09-24 04:55:42 +00:00
// `cargo test` should not rebuild dependencies. It builds the test
// executables with `lto=true` because the tests are built with the
// `--release` flag.
2020-06-10 22:31:36 +00:00
p.cargo("test --release -v")
.with_stderr_unordered(
"\
[FRESH] registry v0.0.1
[FRESH] registry-shared v0.0.1
[FRESH] bar v0.0.0 [..]
[COMPILING] foo [..]
2021-09-24 04:55:42 +00:00
[RUNNING] `rustc --crate-name foo [..]-C lto [..]--test[..]
[RUNNING] `rustc --crate-name a [..]-C lto [..]--test[..]
2020-06-10 22:31:36 +00:00
[FINISHED] [..]
[RUNNING] [..]
[RUNNING] [..]
",
)
.run();
2021-09-24 04:55:42 +00:00
// Building just `bar` causes `registry-shared` to get rebuilt because it
// switches to OnlyObject because it is now only being used with a dylib
// which does not support LTO.
//
// `bar` gets rebuilt because `registry_shared` got rebuilt.
2020-06-10 22:31:36 +00:00
p.cargo("build --release -v --manifest-path bar/Cargo.toml")
.with_stderr_unordered(
"\
[COMPILING] registry-shared v0.0.1
[FRESH] registry v0.0.1
[RUNNING] `rustc --crate-name registry_shared [..]-C embed-bitcode=no[..]
[DIRTY] bar v0.0.0 ([..]): dependency info changed
2020-06-10 22:31:36 +00:00
[COMPILING] bar [..]
[RUNNING] `rustc --crate-name bar [..]--crate-type dylib [..]-C embed-bitcode=no[..]
2020-06-10 22:31:36 +00:00
[FINISHED] [..]
",
)
.run();
2021-09-24 04:55:42 +00:00
// Testing just `bar` causes `registry` to get rebuilt because it switches
// to needing both Object (for the `bar` dylib) and Bitcode (for the test
// built with LTO).
//
// `bar` the dylib gets rebuilt because `registry` got rebuilt.
2020-06-10 22:31:36 +00:00
p.cargo("test --release -v --manifest-path bar/Cargo.toml")
.with_stderr_unordered(
"\
[FRESH] registry-shared v0.0.1
2021-09-24 04:55:42 +00:00
[COMPILING] registry v0.0.1
[RUNNING] `rustc --crate-name registry [..]
[DIRTY] bar v0.0.0 ([..]): dependency info changed
2020-06-10 22:31:36 +00:00
[COMPILING] bar [..]
2021-09-24 04:55:42 +00:00
[RUNNING] `rustc --crate-name bar [..]--crate-type dylib [..]-C embed-bitcode=no[..]
[RUNNING] `rustc --crate-name bar [..]-C lto [..]--test[..]
[RUNNING] `rustc --crate-name b [..]-C lto [..]--test[..]
2020-06-10 22:31:36 +00:00
[FINISHED] [..]
[RUNNING] [..]
[RUNNING] [..]
",
)
.run();
}
#[cargo_test]
fn test_profile() {
Package::new("bar", "0.0.1")
.file("src/lib.rs", "pub fn foo() -> i32 { 123 } ")
.publish();
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2018"
[profile.test]
lto = 'thin'
[dependencies]
bar = "*"
"#,
)
.file(
"src/lib.rs",
r#"
#[test]
fn t1() {
assert_eq!(123, bar::foo());
}
"#,
)
.build();
p.cargo("test -v")
2020-07-29 05:25:45 +00:00
// unordered because the two `foo` builds start in parallel
.with_stderr_unordered("\
2020-06-10 22:31:36 +00:00
[UPDATING] [..]
[DOWNLOADING] [..]
[DOWNLOADED] [..]
[COMPILING] bar v0.0.1
[RUNNING] `rustc --crate-name bar [..]crate-type lib[..]
[COMPILING] foo [..]
2020-08-27 23:41:43 +00:00
[RUNNING] `rustc --crate-name foo [..]--crate-type lib --emit=dep-info,metadata,link -C linker-plugin-lto[..]
2020-06-10 22:31:36 +00:00
[RUNNING] `rustc --crate-name foo [..]--emit=dep-info,link -C lto=thin [..]--test[..]
[FINISHED] [..]
[RUNNING] [..]
[DOCTEST] foo
[RUNNING] `rustdoc [..]
")
.run();
}
2020-08-27 23:41:43 +00:00
#[cargo_test]
fn doctest() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2018"
[profile.release]
lto = true
[dependencies]
bar = { path = "bar" }
"#,
)
.file(
"src/lib.rs",
r#"
/// Foo!
///
/// ```
/// foo::foo();
/// ```
pub fn foo() { bar::bar(); }
"#,
)
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
.file(
"bar/src/lib.rs",
r#"
pub fn bar() { println!("hi!"); }
"#,
)
.build();
p.cargo("test --doc --release -v")
2021-09-24 04:55:42 +00:00
.with_stderr_contains("[..]`rustc --crate-name bar[..]-C linker-plugin-lto[..]")
.with_stderr_contains("[..]`rustc --crate-name foo[..]-C linker-plugin-lto[..]")
2020-08-27 23:41:43 +00:00
// embed-bitcode should be harmless here
2021-09-24 04:55:42 +00:00
.with_stderr_contains("[..]`rustdoc [..]-C lto[..]")
2020-08-27 23:41:43 +00:00
.run();
// Try with bench profile.
p.cargo("test --doc --release -v")
.env("CARGO_PROFILE_BENCH_LTO", "true")
2021-09-24 04:55:42 +00:00
.with_stderr_unordered(
"\
[FRESH] bar v0.1.0 [..]
[FRESH] foo v0.1.0 [..]
[FINISHED] release [..]
[DOCTEST] foo
[RUNNING] `rustdoc [..]-C lto[..]
",
)
2020-08-27 23:41:43 +00:00
.run();
}
2020-10-05 15:15:32 +00:00
#[cargo_test]
fn dylib_rlib_bin() {
// dylib+rlib linked with a binary
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
[lib]
crate-type = ["dylib", "rlib"]
[profile.release]
lto = true
"#,
)
.file("src/lib.rs", "pub fn foo() { println!(\"hi!\"); }")
2021-11-29 18:04:15 +00:00
.file("src/bin/ferret.rs", "fn main() { foo::foo(); }")
2020-10-05 15:15:32 +00:00
.build();
let output = p.cargo("build --release -v").exec_with_output().unwrap();
verify_lto(
&output,
"foo",
"--crate-type dylib --crate-type rlib",
Lto::ObjectAndBitcode,
);
2021-11-29 18:04:15 +00:00
verify_lto(&output, "ferret", "--crate-type bin", Lto::Run(None));
2020-10-05 15:15:32 +00:00
}
2020-10-05 15:56:22 +00:00
#[cargo_test]
fn fresh_swapping_commands() {
// In some rare cases, different commands end up building dependencies
// with different LTO settings. This checks that it doesn't cause the
// cache to thrash in that scenario.
Package::new("bar", "1.0.0").publish();
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
[dependencies]
bar = "1.0"
[profile.release]
lto = true
"#,
)
.file("src/lib.rs", "pub fn foo() { println!(\"hi!\"); }")
.build();
p.cargo("build --release -v")
.with_stderr(
"\
[UPDATING] [..]
[DOWNLOADING] crates ...
[DOWNLOADED] bar v1.0.0 [..]
[COMPILING] bar v1.0.0
[RUNNING] `rustc --crate-name bar [..]-C linker-plugin-lto[..]
[COMPILING] foo v0.1.0 [..]
[RUNNING] `rustc --crate-name foo src/lib.rs [..]-C linker-plugin-lto[..]
[FINISHED] [..]
",
)
.run();
p.cargo("test --release -v")
.with_stderr_unordered(
"\
2021-09-24 04:55:42 +00:00
[FRESH] bar v1.0.0
2020-10-05 15:56:22 +00:00
[COMPILING] foo v0.1.0 [..]
2021-09-24 04:55:42 +00:00
[RUNNING] `rustc --crate-name foo src/lib.rs [..]-C lto[..]--test[..]
2020-10-05 15:56:22 +00:00
[FINISHED] [..]
[RUNNING] `[..]/foo[..]`
[DOCTEST] foo
2021-09-24 04:55:42 +00:00
[RUNNING] `rustdoc [..]-C lto[..]
2020-10-05 15:56:22 +00:00
",
)
.run();
p.cargo("build --release -v")
.with_stderr(
"\
[FRESH] bar v1.0.0
[FRESH] foo [..]
[FINISHED] [..]
",
)
.run();
p.cargo("test --release -v --no-run -v")
.with_stderr(
"\
[FRESH] bar v1.0.0
[FRESH] foo [..]
[FINISHED] [..]
[EXECUTABLE] `[..]/target/release/deps/foo-[..][EXE]`
2020-10-05 15:56:22 +00:00
",
)
.run();
}