77//! goes along from the output of the previous stage.
88
99use std:: borrow:: Cow ;
10- use std:: collections:: HashSet ;
10+ use std:: collections:: { BTreeMap , HashSet } ;
1111use std:: ffi:: OsStr ;
1212use std:: io:: BufReader ;
1313use std:: io:: prelude:: * ;
@@ -1576,17 +1576,77 @@ impl Step for RustcLink {
15761576 }
15771577}
15781578
1579+ /// Set of `libgccjit` dylibs that can be used by `cg_gcc` to compile code for a set of targets.
1580+ #[ derive( Clone ) ]
1581+ pub struct GccDylibSet {
1582+ dylibs : BTreeMap < TargetSelection , GccOutput > ,
1583+ }
1584+
1585+ impl GccDylibSet {
1586+ /// Install the libgccjit dylibs to the corresponding target directories of the given compiler.
1587+ pub fn install_to ( & self , builder : & Builder < ' _ > , compiler : Compiler ) {
1588+ if builder. config . dry_run ( ) {
1589+ return ;
1590+ }
1591+
1592+ // <rustc>/lib
1593+ let lib_sysroot = builder. rustc_libdir ( compiler) ;
1594+
1595+ for ( target, libgccjit) in & self . dylibs {
1596+ let libgccjit = libgccjit. libgccjit ( ) ;
1597+ let target_filename = libgccjit. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
1598+
1599+ // If we build libgccjit ourselves, then `libgccjit` can actually be a symlink.
1600+ // In that case, we have to resolve it first, otherwise we'd create a symlink to a
1601+ // symlink, which wouldn't work.
1602+ let actual_libgccjit_path = t ! (
1603+ libgccjit. canonicalize( ) ,
1604+ format!( "Cannot find libgccjit at {}" , libgccjit. display( ) )
1605+ ) ;
1606+
1607+ // <rustc>/lib/rustlib/<target>/lib/libgccjit.so
1608+ let dest_dir = lib_sysroot. join ( "rustlib" ) . join ( target) . join ( "lib" ) ;
1609+ t ! ( fs:: create_dir_all( & dest_dir) ) ;
1610+ let dst = dest_dir. join ( target_filename) ;
1611+ builder. copy_link ( & actual_libgccjit_path, & dst, FileType :: NativeLibrary ) ;
1612+ }
1613+ }
1614+ }
1615+
15791616/// Output of the `compile::GccCodegenBackend` step.
1580- /// It includes the path to the libgccjit library on which this backend depends.
1617+ ///
1618+ /// It contains paths to all built libgccjit libraries on which this backend depends here.
15811619#[ derive( Clone ) ]
15821620pub struct GccCodegenBackendOutput {
15831621 stamp : BuildStamp ,
1584- gcc : GccOutput ,
1622+ dylib_set : GccDylibSet ,
15851623}
15861624
1625+ /// Builds the GCC codegen backend (`cg_gcc`).
1626+ /// The `cg_gcc` backend uses `libgccjit`, which requires a separate build for each
1627+ /// `host -> target` pair. So if you are on linux-x64 and build for linux-aarch64,
1628+ /// you will need at least:
1629+ /// - linux-x64 -> linux-x64 libgccjit (for building host code like proc macros)
1630+ /// - linux-x64 -> linux-aarch64 libgccjit (for the aarch64 target code)
1631+ ///
1632+ /// We model this by having a single cg_gcc for a given host target, which contains one
1633+ /// libgccjit per (host, target) pair.
1634+ /// Note that the host target is taken from `self.compilers.build_compiler.host`.
15871635#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
15881636pub struct GccCodegenBackend {
15891637 compilers : RustcPrivateCompilers ,
1638+ targets : Vec < TargetSelection > ,
1639+ }
1640+
1641+ impl GccCodegenBackend {
1642+ /// Create a cg_gcc backend that can compile code for all targets for which we build the
1643+ /// standard library.
1644+ pub fn for_all_std_targets ( builder : & Builder < ' _ > , compilers : RustcPrivateCompilers ) -> Self {
1645+ let mut targets = builder. targets . clone ( ) ;
1646+ // Sort targets to improve step cache hits
1647+ targets. sort ( ) ;
1648+ Self { compilers, targets }
1649+ }
15901650}
15911651
15921652impl Step for GccCodegenBackend {
@@ -1599,9 +1659,10 @@ impl Step for GccCodegenBackend {
15991659 }
16001660
16011661 fn make_run ( run : RunConfig < ' _ > ) {
1602- run. builder . ensure ( GccCodegenBackend {
1603- compilers : RustcPrivateCompilers :: new ( run. builder , run. builder . top_stage , run. target ) ,
1604- } ) ;
1662+ run. builder . ensure ( GccCodegenBackend :: for_all_std_targets (
1663+ run. builder ,
1664+ RustcPrivateCompilers :: new ( run. builder , run. builder . top_stage , run. target ) ,
1665+ ) ) ;
16051666 }
16061667
16071668 fn run ( self , builder : & Builder < ' _ > ) -> Self :: Output {
@@ -1615,7 +1676,13 @@ impl Step for GccCodegenBackend {
16151676 & CodegenBackendKind :: Gcc ,
16161677 ) ;
16171678
1618- let gcc = builder. ensure ( Gcc { target } ) ;
1679+ let dylib_set = GccDylibSet {
1680+ dylibs : self
1681+ . targets
1682+ . iter ( )
1683+ . map ( |& target| ( target, builder. ensure ( Gcc { target } ) ) )
1684+ . collect ( ) ,
1685+ } ;
16191686
16201687 if builder. config . keep_stage . contains ( & build_compiler. stage ) {
16211688 trace ! ( "`keep-stage` requested" ) ;
@@ -1625,7 +1692,7 @@ impl Step for GccCodegenBackend {
16251692 ) ;
16261693 // Codegen backends are linked separately from this step today, so we don't do
16271694 // anything here.
1628- return GccCodegenBackendOutput { stamp, gcc } ;
1695+ return GccCodegenBackendOutput { stamp, dylib_set } ;
16291696 }
16301697
16311698 let mut cargo = builder:: Cargo :: new (
@@ -1639,15 +1706,21 @@ impl Step for GccCodegenBackend {
16391706 cargo. arg ( "--manifest-path" ) . arg ( builder. src . join ( "compiler/rustc_codegen_gcc/Cargo.toml" ) ) ;
16401707 rustc_cargo_env ( builder, & mut cargo, target) ;
16411708
1642- add_cg_gcc_cargo_flags ( & mut cargo, & gcc) ;
1709+ add_cg_gcc_cargo_flags (
1710+ & mut cargo,
1711+ & dylib_set
1712+ . dylibs
1713+ . get ( & build_compiler. host )
1714+ . expect ( "libgccjit was not build for the host target" ) ,
1715+ ) ;
16431716
16441717 let _guard =
16451718 builder. msg ( Kind :: Build , "codegen backend gcc" , Mode :: Codegen , build_compiler, target) ;
16461719 let files = run_cargo ( builder, cargo, vec ! [ ] , & stamp, vec ! [ ] , false , false ) ;
16471720
16481721 GccCodegenBackendOutput {
16491722 stamp : write_codegen_backend_stamp ( stamp, files, builder. config . dry_run ( ) ) ,
1650- gcc ,
1723+ dylib_set ,
16511724 }
16521725 }
16531726
@@ -2324,12 +2397,14 @@ impl Step for Assemble {
23242397 copy_codegen_backends_to_sysroot ( builder, stamp, target_compiler) ;
23252398 }
23262399 CodegenBackendKind :: Gcc => {
2327- let output =
2328- builder. ensure ( GccCodegenBackend { compilers : prepare_compilers ( ) } ) ;
2400+ let output = builder. ensure ( GccCodegenBackend :: for_all_std_targets (
2401+ builder,
2402+ prepare_compilers ( ) ,
2403+ ) ) ;
23292404 copy_codegen_backends_to_sysroot ( builder, output. stamp , target_compiler) ;
2330- // Also copy libgccjit to the library sysroot, so that it is available for
2331- // the codegen backend.
2332- output. gcc . install_to ( builder, & rustc_libdir ) ;
2405+ // Also copy all requires libgccjit dylibs to the corresponding
2406+ // library sysroots, so that they are available for the codegen backend.
2407+ output. dylib_set . install_to ( builder, target_compiler ) ;
23332408 }
23342409 CodegenBackendKind :: Llvm | CodegenBackendKind :: Custom ( _) => continue ,
23352410 }
0 commit comments