From 0a468a4f3b1c9dea9b31ca51cebd3db58d65e771 Mon Sep 17 00:00:00 2001 From: Ivan Lozano Date: Mon, 13 May 2024 21:03:34 -0400 Subject: rust: made-to-order rust staticlibs Whenever any two Rust static libraries are included as static libraries anywhere in a CC dependency tree, we sometimes get duplicate symbol errors. To avoid this, we no longer directly link multiple rust static libs to CC modules. Instead, we build rust_ffi_rlib modules and produce the actual static library that gets linked against the CC module based on that CC module's full list of Rust rlib dependencies. This introduces a new static_rlibs property for cc modules to define the rust_ffi_rlib dependencies, which are then used to generate the module above. This CL is intended to deprecate rust_ffi_static. It leaves rust_ffi_static and rust_ffi static variants in place until the remaining rust_ffi_static declarations and uses can be removed. In the meantime, rust_ffi_static produces rust_ffi_rlib variants as well to make the transition easier. Bug: 254469782 Test: m # with no changes Test: m libapexsupport # with static_rlibs Test: m libunwindstack # with static_rlibs Test: m netsimd # with static_rlibs, no duplicate symbols Test: m blueprint_tests # New Soong tests Change-Id: I47e27ac967ef0cad46d398ebf59d8275929ae28a --- rust/library.go | 149 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 110 insertions(+), 39 deletions(-) (limited to 'rust/library.go') diff --git a/rust/library.go b/rust/library.go index 7e5d4c495..730000114 100644 --- a/rust/library.go +++ b/rust/library.go @@ -37,10 +37,15 @@ func init() { android.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory) android.RegisterModuleType("rust_ffi", RustFFIFactory) android.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory) - android.RegisterModuleType("rust_ffi_static", RustFFIStaticFactory) + android.RegisterModuleType("rust_ffi_rlib", RustFFIRlibFactory) android.RegisterModuleType("rust_ffi_host", RustFFIHostFactory) android.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory) - android.RegisterModuleType("rust_ffi_host_static", RustFFIStaticHostFactory) + android.RegisterModuleType("rust_ffi_host_rlib", RustFFIRlibHostFactory) + + // TODO: Remove when all instances of rust_ffi_static have been switched to rust_ffi_rlib + // Alias rust_ffi_static to the combined rust_ffi_rlib factory + android.RegisterModuleType("rust_ffi_static", RustFFIStaticRlibFactory) + android.RegisterModuleType("rust_ffi_host_static", RustFFIStaticRlibHostFactory) } type VariantLibraryProperties struct { @@ -104,6 +109,8 @@ type libraryDecorator struct { includeDirs android.Paths sourceProvider SourceProvider + isFFI bool + // table-of-contents file for cdylib crates to optimize out relinking when possible tocFile android.OptionalPath } @@ -143,6 +150,8 @@ type libraryInterface interface { BuildOnlyShared() toc() android.OptionalPath + + isFFILibrary() bool } func (library *libraryDecorator) nativeCoverage() bool { @@ -250,7 +259,7 @@ func (library *libraryDecorator) autoDep(ctx android.BottomUpMutatorContext) aut } func (library *libraryDecorator) stdLinkage(ctx *depsContext) RustLinkage { - if library.static() || library.MutatedProperties.VariantIsStaticStd { + if library.static() || library.MutatedProperties.VariantIsStaticStd || (library.rlib() && library.isFFILibrary()) { return RlibLinkage } else if library.baseCompiler.preferRlib() { return RlibLinkage @@ -270,8 +279,8 @@ func RustLibraryFactory() android.Module { return module.Init() } -// rust_ffi produces all FFI variants (rust_ffi_shared and -// rust_ffi_static). +// rust_ffi produces all FFI variants (rust_ffi_shared, rust_ffi_static, and +// rust_ffi_rlib). func RustFFIFactory() android.Module { module, library := NewRustLibrary(android.HostAndDeviceSupported) library.BuildOnlyFFI() @@ -300,14 +309,6 @@ func RustFFISharedFactory() android.Module { return module.Init() } -// rust_ffi_static produces a static library (Rust crate type -// "staticlib"). -func RustFFIStaticFactory() android.Module { - module, library := NewRustLibrary(android.HostAndDeviceSupported) - library.BuildOnlyStatic() - return module.Init() -} - // rust_library_host produces all Rust variants for the host // (rust_library_dylib_host and rust_library_rlib_host). func RustLibraryHostFactory() android.Module { @@ -317,7 +318,7 @@ func RustLibraryHostFactory() android.Module { } // rust_ffi_host produces all FFI variants for the host -// (rust_ffi_static_host and rust_ffi_shared_host). +// (rust_ffi_rlib_host, rust_ffi_static_host, and rust_ffi_shared_host). func RustFFIHostFactory() android.Module { module, library := NewRustLibrary(android.HostSupported) library.BuildOnlyFFI() @@ -340,14 +341,6 @@ func RustLibraryRlibHostFactory() android.Module { return module.Init() } -// rust_ffi_static_host produces a static library for the host (Rust -// crate type "staticlib"). -func RustFFIStaticHostFactory() android.Module { - module, library := NewRustLibrary(android.HostSupported) - library.BuildOnlyStatic() - return module.Init() -} - // rust_ffi_shared_host produces an shared library for the host (Rust // crate type "cdylib"). func RustFFISharedHostFactory() android.Module { @@ -356,11 +349,51 @@ func RustFFISharedHostFactory() android.Module { return module.Init() } +// rust_ffi_rlib_host produces an rlib for the host (Rust crate +// type "rlib"). +func RustFFIRlibHostFactory() android.Module { + module, library := NewRustLibrary(android.HostSupported) + library.BuildOnlyRlibStatic() + + library.isFFI = true + return module.Init() +} + +// rust_ffi_rlib produces an rlib (Rust crate type "rlib"). +func RustFFIRlibFactory() android.Module { + module, library := NewRustLibrary(android.HostAndDeviceSupported) + library.BuildOnlyRlib() + + library.isFFI = true + return module.Init() +} + +// rust_ffi_static produces a staticlib and an rlib variant +func RustFFIStaticRlibFactory() android.Module { + module, library := NewRustLibrary(android.HostAndDeviceSupported) + library.BuildOnlyRlibStatic() + + library.isFFI = true + return module.Init() +} + +// rust_ffi_static_host produces a staticlib and an rlib variant for the host +func RustFFIStaticRlibHostFactory() android.Module { + module, library := NewRustLibrary(android.HostSupported) + library.BuildOnlyRlibStatic() + + library.isFFI = true + return module.Init() +} + func (library *libraryDecorator) BuildOnlyFFI() { library.MutatedProperties.BuildDylib = false - library.MutatedProperties.BuildRlib = false + // we build rlibs for later static ffi linkage. + library.MutatedProperties.BuildRlib = true library.MutatedProperties.BuildShared = true library.MutatedProperties.BuildStatic = true + + library.isFFI = true } func (library *libraryDecorator) BuildOnlyRust() { @@ -384,11 +417,21 @@ func (library *libraryDecorator) BuildOnlyRlib() { library.MutatedProperties.BuildStatic = false } +func (library *libraryDecorator) BuildOnlyRlibStatic() { + library.MutatedProperties.BuildDylib = false + library.MutatedProperties.BuildRlib = true + library.MutatedProperties.BuildShared = false + library.MutatedProperties.BuildStatic = true + library.isFFI = true +} + func (library *libraryDecorator) BuildOnlyStatic() { library.MutatedProperties.BuildRlib = false library.MutatedProperties.BuildDylib = false library.MutatedProperties.BuildShared = false library.MutatedProperties.BuildStatic = true + + library.isFFI = true } func (library *libraryDecorator) BuildOnlyShared() { @@ -396,6 +439,12 @@ func (library *libraryDecorator) BuildOnlyShared() { library.MutatedProperties.BuildDylib = false library.MutatedProperties.BuildStatic = false library.MutatedProperties.BuildShared = true + + library.isFFI = true +} + +func (library *libraryDecorator) isFFILibrary() bool { + return library.isFFI } func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) { @@ -480,10 +529,11 @@ func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) F flags = CommonLibraryCompilerFlags(ctx, flags) - if library.shared() || library.static() { + if library.isFFI { library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...) library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Export_include_dirs)...) } + if library.shared() { if ctx.Darwin() { flags.LinkFlags = append( @@ -509,6 +559,9 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa deps.srcProviderFiles = append(deps.srcProviderFiles, library.sourceProvider.Srcs()...) } + // Ensure link dirs are not duplicated + deps.linkDirs = android.FirstUniqueStrings(deps.linkDirs) + // Calculate output filename if library.rlib() { fileName = library.getStem(ctx) + ctx.toolchain().RlibSuffix() @@ -564,9 +617,10 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa library.flagExporter.exportLinkObjects(deps.linkObjects...) } - if library.static() || library.shared() { + // Since we have FFI rlibs, we need to collect their includes as well + if library.static() || library.shared() || library.rlib() { android.SetProvider(ctx, cc.FlagExporterInfoProvider, cc.FlagExporterInfo{ - IncludeDirs: library.includeDirs, + IncludeDirs: android.FirstUniquePaths(library.includeDirs), }) } @@ -681,6 +735,11 @@ func LibraryMutator(mctx android.BottomUpMutatorContext) { return } + // Don't produce rlib/dylib/source variants for shared or static variants + if library.shared() || library.static() { + return + } + var variants []string // The source variant is used for SourceProvider modules. The other variants (i.e. rlib and dylib) // depend on this variant. It must be the first variant to be declared. @@ -720,6 +779,9 @@ func LibraryMutator(mctx android.BottomUpMutatorContext) { // The source variant does not produce any library. // Disable the compilation steps. v.(*Module).compiler.SetDisabled() + case "": + // if there's an empty variant, alias it so it is the default variant + mctx.AliasVariation("") } } @@ -744,20 +806,29 @@ func LibstdMutator(mctx android.BottomUpMutatorContext) { case libraryInterface: // Only create a variant if a library is actually being built. if library.rlib() && !library.sysroot() { - variants := []string{"rlib-std", "dylib-std"} - modules := mctx.CreateLocalVariations(variants...) - - rlib := modules[0].(*Module) - dylib := modules[1].(*Module) - rlib.compiler.(libraryInterface).setRlibStd() - dylib.compiler.(libraryInterface).setDylibStd() - if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation { - // TODO(b/165791368) - // Disable rlibs that link against dylib-std on vendor ramdisk variations until those dylib - // variants are properly supported. - dylib.Disable() + // If this is a rust_ffi variant it only needs rlib-std + if library.isFFILibrary() { + variants := []string{"rlib-std"} + modules := mctx.CreateLocalVariations(variants...) + rlib := modules[0].(*Module) + rlib.compiler.(libraryInterface).setRlibStd() + rlib.Properties.RustSubName += RlibStdlibSuffix + } else { + variants := []string{"rlib-std", "dylib-std"} + modules := mctx.CreateLocalVariations(variants...) + + rlib := modules[0].(*Module) + dylib := modules[1].(*Module) + rlib.compiler.(libraryInterface).setRlibStd() + dylib.compiler.(libraryInterface).setDylibStd() + if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation { + // TODO(b/165791368) + // Disable rlibs that link against dylib-std on vendor ramdisk variations until those dylib + // variants are properly supported. + dylib.Disable() + } + rlib.Properties.RustSubName += RlibStdlibSuffix } - rlib.Properties.RustSubName += RlibStdlibSuffix } } } -- cgit v1.2.3-59-g8ed1b