@@ -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