Skip to content

Commit 819349d

Browse files
committed
Pass -Zembed-metadata to rustc
1 parent 2a5f670 commit 819349d

File tree

6 files changed

+188
-9
lines changed

6 files changed

+188
-9
lines changed

src/cargo/core/compiler/build_context/target_info.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -613,9 +613,19 @@ impl TargetInfo {
613613
}
614614
}
615615
}
616-
if !result.is_empty() && !crate_types.iter().any(|ct| ct.requires_upstream_objects()) {
617-
// Only add rmeta if pipelining.
618-
result.push(FileType::new_rmeta());
616+
if !result.is_empty() {
617+
if !crate_types.iter().any(|ct| ct.requires_upstream_objects()) {
618+
// Only add rmeta if pipelining...
619+
result.push(FileType::new_rmeta());
620+
} else if crate_types
621+
.iter()
622+
.any(|ct| ct.benefits_from_split_metadata())
623+
{
624+
// ...or when we apply -Zembed-metadata=no to the unit.
625+
// TODO: should we thread through the information if we use
626+
// embed-metadata?
627+
result.push(FileType::new_rmeta());
628+
}
619629
}
620630
Ok((result, unsupported))
621631
}

src/cargo/core/compiler/crate_type.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,38 @@ impl CrateType {
7676
// Everything else, however, is some form of "linkable output" or
7777
// something that requires upstream object files.
7878
}
79+
80+
/// Returns whether production of this crate type could benefit from splitting metadata
81+
/// into a .rmeta file.
82+
///
83+
/// See also [`TargetKind::benefits_from_split_metadata`].
84+
///
85+
/// [`TargetKind::benefits_from_split_metadata`]: crate::core::manifest::TargetKind::benefits_from_split_metadata
86+
pub fn benefits_from_split_metadata(&self) -> bool {
87+
match self {
88+
// rlib/libs generate .rmeta files for pipelined compilation.
89+
// If we also include metadata inside of them, we waste disk space, since the metadata
90+
// will be located both in the lib/rlib and the .rmeta file.
91+
CrateType::Lib |
92+
CrateType::Rlib |
93+
// Dylibs do not have to contain metadata when they are used as a runtime dependency.
94+
// If we split the metadata into a separate .rmeta file, the dylib file (that
95+
// can be shipped as a runtime dependency) can be smaller.
96+
CrateType::Dylib => true,
97+
// Proc macros contains metadata that specifies what macro functions are available in
98+
// it, but the metadata is typically very small. The metadata of proc macros is also
99+
// self-contained (unlike rlibs/dylibs), so let's not unnecessarily split it into
100+
// multiple files.
101+
CrateType::ProcMacro |
102+
// cdylib and staticlib produce artifacts that are used through the C ABI and do not
103+
// contain Rust-specific metadata.
104+
CrateType::Cdylib |
105+
CrateType::Staticlib |
106+
// Binaries also do not contain metadata
107+
CrateType::Bin |
108+
CrateType::Other(_) => false
109+
}
110+
}
79111
}
80112

81113
impl fmt::Display for CrateType {

src/cargo/core/compiler/mod.rs

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,15 +1102,34 @@ fn build_base_args(
11021102
}
11031103
}
11041104

1105+
let use_embed_metadata = use_embed_metadata(build_runner);
11051106
if unit.mode.is_check() {
11061107
cmd.arg("--emit=dep-info,metadata");
1107-
} else if !unit.requires_upstream_objects() {
1108-
// Always produce metadata files for rlib outputs. Metadata may be used
1109-
// in this session for a pipelined compilation, or it may be used in a
1110-
// future Cargo session as part of a pipelined compile.
1111-
cmd.arg("--emit=dep-info,metadata,link");
1108+
} else if use_embed_metadata {
1109+
// Nightly rustc supports the -Zembed-metadata=no flag, which tells it to avoid including
1110+
// full metadata in rlib/dylib artifacts, to save space on disk. In this case, metadata
1111+
// will only be stored in .rmeta files.
1112+
// When we use this flag, we should also pass --emit=metadata to all artifacts that
1113+
// contain useful metadata (rlib/dylib/proc macros), so that a .rmeta file is actually
1114+
// generated. If we didn't do this, the full metadata would not get written anywhere.
1115+
// However, we do not want to pass --emit=metadata to artifacts that never produce useful
1116+
// metadata, such as binaries, because that would just unnecessarily create empty .rmeta
1117+
// files on disk.
1118+
if unit.benefits_from_split_metadata() {
1119+
cmd.arg("--emit=dep-info,metadata,link");
1120+
cmd.args(&["-Z", "embed-metadata=no"]);
1121+
} else {
1122+
cmd.arg("--emit=dep-info,link");
1123+
}
11121124
} else {
1113-
cmd.arg("--emit=dep-info,link");
1125+
// If we don't use -Zembed-metadata=no, we emit .rmeta files only for rlib outputs.
1126+
// This metadata may be used in this session for a pipelined compilation, or it may
1127+
// be used in a future Cargo session as part of a pipelined compile.
1128+
if !unit.requires_upstream_objects() {
1129+
cmd.arg("--emit=dep-info,metadata,link");
1130+
} else {
1131+
cmd.arg("--emit=dep-info,link");
1132+
}
11141133
}
11151134

11161135
let prefer_dynamic = (unit.target.for_host() && !unit.target.is_custom_build())
@@ -1609,6 +1628,8 @@ pub fn extern_args(
16091628
let mut result = Vec::new();
16101629
let deps = build_runner.unit_deps(unit);
16111630

1631+
let use_embed_metadata = use_embed_metadata(build_runner);
1632+
16121633
// Closure to add one dependency to `result`.
16131634
let mut link_to =
16141635
|dep: &UnitDep, extern_crate_name: InternedString, noprelude: bool| -> CargoResult<()> {
@@ -1658,6 +1679,12 @@ pub fn extern_args(
16581679
if output.flavor == FileFlavor::Linkable {
16591680
pass(&output.path);
16601681
}
1682+
// If we use -Zembed-metadata=no, we also need to pass the path to the
1683+
// corresponding .rmeta file to the linkable artifact, because the
1684+
// normal dependency (rlib) doesn't contain the full metadata.
1685+
else if use_embed_metadata && output.flavor == FileFlavor::Rmeta {
1686+
pass(&output.path);
1687+
}
16611688
}
16621689
}
16631690
Ok(())
@@ -1684,6 +1711,11 @@ fn envify(s: &str) -> String {
16841711
.collect()
16851712
}
16861713

1714+
/// Returns true if -Zembed-metadata=no mode should be used when compiling Rust artifacts.
1715+
fn use_embed_metadata(build_runner: &BuildRunner<'_, '_>) -> bool {
1716+
build_runner.bcx.gctx.nightly_features_allowed
1717+
}
1718+
16871719
/// Configuration of the display of messages emitted by the compiler,
16881720
/// e.g. diagnostics, warnings, errors, and message caching.
16891721
struct OutputOptions {

src/cargo/core/compiler/unit.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@ impl UnitInner {
125125
self.mode.is_any_test() || self.target.kind().requires_upstream_objects()
126126
}
127127

128+
/// Returns whether compilation of this unit could benefit from splitting metadata
129+
/// into a .rmeta file.
130+
pub fn benefits_from_split_metadata(&self) -> bool {
131+
matches!(self.mode, CompileMode::Build) && self.target.kind().benefits_from_split_metadata()
132+
}
133+
128134
/// Returns whether or not this is a "local" package.
129135
///
130136
/// A "local" package is one that the user can likely edit, or otherwise

src/cargo/core/manifest.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,17 @@ impl TargetKind {
279279
}
280280
}
281281

282+
/// Returns whether production of this artifact could benefit from splitting metadata
283+
/// into a .rmeta file.
284+
pub fn benefits_from_split_metadata(&self) -> bool {
285+
match self {
286+
TargetKind::Lib(kinds) | TargetKind::ExampleLib(kinds) => {
287+
kinds.iter().any(|k| k.benefits_from_split_metadata())
288+
}
289+
_ => false,
290+
}
291+
}
292+
282293
/// Returns the arguments suitable for `--crate-type` to pass to rustc.
283294
pub fn rustc_crate_types(&self) -> Vec<CrateType> {
284295
match self {

tests/testsuite/build.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6749,3 +6749,91 @@ fn renamed_uplifted_artifact_remains_unmodified_after_rebuild() {
67496749
let not_the_same = !same_file::is_same_file(bin, renamed_bin).unwrap();
67506750
assert!(not_the_same, "renamed uplifted artifact must be unmodified");
67516751
}
6752+
6753+
#[cargo_test(nightly, reason = "-Zembed-metadata is nightly only")]
6754+
fn embed_metadata() {
6755+
let p = project()
6756+
.file(
6757+
"Cargo.toml",
6758+
r#"
6759+
[package]
6760+
6761+
name = "foo"
6762+
version = "0.5.0"
6763+
edition = "2015"
6764+
6765+
[dependencies.bar]
6766+
path = "bar"
6767+
"#,
6768+
)
6769+
.file("src/main.rs", &main_file(r#""{}", bar::gimme()"#, &[]))
6770+
.file("bar/Cargo.toml", &basic_lib_manifest("bar"))
6771+
.file(
6772+
"bar/src/bar.rs",
6773+
r#"
6774+
pub fn gimme() -> &'static str {
6775+
"test passed"
6776+
}
6777+
"#,
6778+
)
6779+
.build();
6780+
6781+
p.cargo("build")
6782+
.masquerade_as_nightly_cargo(&["-Zembed-metadata"])
6783+
.arg("-v")
6784+
.with_stderr_contains("[RUNNING] `[..]-Z embed-metadata=no[..]`")
6785+
.with_stderr_contains(
6786+
"[RUNNING] `[..]--extern bar=[ROOT]/foo/target/debug/deps/libbar-[HASH].rmeta[..]`",
6787+
)
6788+
.run();
6789+
}
6790+
6791+
// Make sure that cargo passes --extern=<dep>.rmeta even if <dep>
6792+
// is compiled as a dylib.
6793+
#[cargo_test(nightly, reason = "-Zembed-metadata is nightly only")]
6794+
fn embed_metadata_dylib_dep() {
6795+
let p = project()
6796+
.file(
6797+
"Cargo.toml",
6798+
r#"
6799+
[package]
6800+
name = "foo"
6801+
version = "0.5.0"
6802+
edition = "2015"
6803+
6804+
[dependencies.bar]
6805+
path = "bar"
6806+
"#,
6807+
)
6808+
.file("src/main.rs", &main_file(r#""{}", bar::gimme()"#, &[]))
6809+
.file(
6810+
"bar/Cargo.toml",
6811+
r#"
6812+
[package]
6813+
name = "bar"
6814+
version = "0.5.0"
6815+
edition = "2015"
6816+
6817+
[lib]
6818+
crate-type = ["dylib"]
6819+
"#,
6820+
)
6821+
.file(
6822+
"bar/src/lib.rs",
6823+
r#"
6824+
pub fn gimme() -> &'static str {
6825+
"test passed"
6826+
}
6827+
"#,
6828+
)
6829+
.build();
6830+
6831+
p.cargo("build")
6832+
.masquerade_as_nightly_cargo(&["-Zembed-metadata"])
6833+
.arg("-v")
6834+
.with_stderr_contains("[RUNNING] `[..]-Z embed-metadata=no[..]`")
6835+
.with_stderr_contains(
6836+
"[RUNNING] `[..]--extern bar=[ROOT]/foo/target/debug/deps/libbar.rmeta[..]`",
6837+
)
6838+
.run();
6839+
}

0 commit comments

Comments
 (0)