Skip to content

Commit ede36c4

Browse files
proggeramlugRalph Kuepper
andauthored
fix(windows): preserve current Rust UI codegen units (#8022)
* fix(windows): preserve current Rust UI codegen units * docs(changelog): note Windows UI COFF export fix --------- Co-authored-by: Ralph Kuepper <ralph@skelpo.com>
1 parent 410dadd commit ede36c4

2 files changed

Lines changed: 48 additions & 4 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
### Windows UI links current Rust codegen archives again
2+
3+
Windows `perry/ui` builds no longer lose every public `perry_ui_*` export
4+
while trimming duplicate COFF archive members. The trimmer now recognizes the
5+
opaque `.rcgu.o` member names emitted by current Rust toolchains, extracts all
6+
of the UI crate's codegen units, and continues to exclude non-codegen allocator
7+
members.

crates/perry/src/commands/compile/strip_dedup.rs

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -444,15 +444,26 @@ fn is_windows_import_archive_member(member: &str) -> bool {
444444
})
445445
}
446446

447+
/// Whether an rlib archive member is one of rustc's codegen units.
448+
///
449+
/// Rust currently names these members `<crate>.<opaque>.<cgu>.rcgu.o`; older
450+
/// toolchains also put a literal `-cgu.` or `.cgu.` segment before the same
451+
/// suffix. Checking for those older segments caused every UI codegen unit
452+
/// produced by current Windows toolchains to be mistaken for an allocator
453+
/// shim, leaving the rebuilt archive without any `perry_ui_*` exports.
454+
fn is_rust_codegen_unit(member: &str) -> bool {
455+
member.ends_with(".rcgu.o")
456+
}
457+
447458
/// On Windows, build a trimmed UI lib using the rlib (not staticlib).
448459
///
449460
/// perry-ui-windows builds as both rlib and staticlib. The staticlib bundles
450461
/// ALL transitive deps (std, alloc, core, perry-runtime -- 314 objects).
451462
/// perry-stdlib also bundles these. Linking both causes hundreds of duplicate
452463
/// symbols, and /FORCE:MULTIPLE produces corrupt binaries.
453464
///
454-
/// The rlib contains only the UI crate's own code (1 object). We extract it
455-
/// and combine with UI-only deps (windows, serde, regex...) from the staticlib.
465+
/// The rlib contains only the UI crate's own code (one or more CGU objects).
466+
/// We extract it and combine with UI-only deps (windows, serde, regex...) from the staticlib.
456467
/// All shared deps come from perry-stdlib. No /FORCE:MULTIPLE needed.
457468
///
458469
/// **Dedup decision** (Tier 3.1, v0.5.331): when `llvm-nm` is available, drop a
@@ -802,8 +813,7 @@ pub(super) fn strip_duplicate_objects_from_lib(lib_path: &PathBuf) -> Result<Pat
802813
let mut rlib_extracted = 0usize;
803814
let mut rlib_skipped = 0usize;
804815
for (member_index, member) in rlib_objects.iter().enumerate() {
805-
let is_alloc_shim = !member.contains(".cgu.") && !member.contains("-cgu.");
806-
if is_alloc_shim {
816+
if !is_rust_codegen_unit(member) {
807817
rlib_skipped += 1;
808818
continue;
809819
}
@@ -1869,6 +1879,14 @@ empty_marker.o:
18691879
find_llvm_tool_or_beside_lld("llvm-nm").expect("Windows LLVM must provide llvm-nm");
18701880
let runtime = temp.path().join("perry_runtime.lib");
18711881
let ui = temp.path().join("perry_ui_windows.lib");
1882+
let ui_rlib = temp.path().join("libperry_ui_windows.rlib");
1883+
// Current rustc uses opaque CGU components such as
1884+
// `.1v150fxu9jccif28r12uax7fb.02s2fqd.rcgu.o`, without the literal
1885+
// `.cgu.` / `-cgu.` segments recognized by the old extraction code.
1886+
let current_rustc_cgu = temp
1887+
.path()
1888+
.join("perry_ui_windows-deadbeef.opaque.codegen.rcgu.o");
1889+
std::fs::copy(&unique_object, &current_rustc_cgu).unwrap();
18721890
rebuild_archive(
18731891
&llvm_ar,
18741892
&runtime,
@@ -1883,13 +1901,32 @@ empty_marker.o:
18831901
true,
18841902
)
18851903
.unwrap();
1904+
rebuild_archive(
1905+
&llvm_ar,
1906+
&ui_rlib,
1907+
std::slice::from_ref(&current_rustc_cgu),
1908+
true,
1909+
)
1910+
.unwrap();
18861911

18871912
let trimmed = strip_duplicate_objects_from_lib(&ui).expect("COFF dedup must succeed");
18881913
let symbols = collect_archive_symbols_flat(&llvm_nm, &trimmed);
18891914
assert!(symbols.contains("ui_only_symbol"));
18901915
assert!(!symbols.contains("runtime_canonical"));
18911916
}
18921917

1918+
#[test]
1919+
fn rust_codegen_unit_recognizes_current_and_legacy_member_names() {
1920+
assert!(super::is_rust_codegen_unit(
1921+
"perry_ui_windows-deadbeef.opaque.codegen.rcgu.o"
1922+
));
1923+
assert!(super::is_rust_codegen_unit(
1924+
"perry_ui_windows-deadbeef.perry_ui_windows.hash-cgu.0.rcgu.o"
1925+
));
1926+
assert!(!super::is_rust_codegen_unit("allocator_shim.o"));
1927+
assert!(!super::is_rust_codegen_unit("lib.rmeta"));
1928+
}
1929+
18931930
#[test]
18941931
fn extracted_path_qualified_archive_member_falls_back_to_basename() {
18951932
let temp = tempfile::tempdir().unwrap();

0 commit comments

Comments
 (0)