// Copyright 2019 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package rust import ( "errors" "fmt" "regexp" "strings" "github.com/google/blueprint" "github.com/google/blueprint/depset" "android/soong/android" "android/soong/cc" cc_config "android/soong/cc/config" ) var ( RlibStdlibSuffix = ".rlib-std" ) func init() { android.RegisterModuleType("rust_library", RustLibraryFactory) android.RegisterModuleType("rust_library_dylib", RustLibraryDylibFactory) android.RegisterModuleType("rust_library_rlib", RustLibraryRlibFactory) android.RegisterModuleType("rust_library_host", RustLibraryHostFactory) android.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory) android.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory) android.RegisterModuleType("rust_ffi", RustFFIFactory) android.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory) android.RegisterModuleType("rust_ffi_host", RustFFIHostFactory) android.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory) android.RegisterModuleType("rust_ffi_static", RustLibraryRlibFactory) android.RegisterModuleType("rust_ffi_host_static", RustLibraryRlibHostFactory) } type VariantLibraryProperties struct { Enabled *bool `android:"arch_variant"` Srcs []string `android:"path,arch_variant"` } type LibraryCompilerProperties struct { Rlib VariantLibraryProperties `android:"arch_variant"` Dylib VariantLibraryProperties `android:"arch_variant"` Shared VariantLibraryProperties `android:"arch_variant"` Static VariantLibraryProperties `android:"arch_variant"` // TODO: Remove this when all instances of Include_dirs have been removed from rust_ffi modules. // path to include directories to pass to cc_* modules, only relevant for static/shared variants (deprecated, use export_include_dirs instead). Include_dirs []string `android:"path,arch_variant"` // path to include directories to export to cc_* modules, only relevant for static/shared variants. Export_include_dirs []string `android:"path,arch_variant"` // Version script to pass to the linker. By default this will replace the // implicit rustc emitted version script to mirror expected behavior in CC. // This is only relevant for rust_ffi_shared modules which are exposing a // versioned C API. Version_script *string `android:"path,arch_variant"` // A version_script formatted text file with additional symbols to export // for rust shared or dylibs which the rustc compiler does not automatically // export, e.g. additional symbols from whole_static_libs. Unlike // Version_script, this is not meant to imply a stable API. Extra_exported_symbols *string `android:"path,arch_variant"` // Whether this library is part of the Rust toolchain sysroot. Sysroot *bool // Deprecated - exclude this rust_ffi target from being included in APEXes. // TODO(b/362509506): remove this once all apex_exclude uses are switched to stubs. Apex_exclude *bool // Generate stubs to make this library accessible to APEXes. // Can only be set for modules producing shared libraries. Stubs cc.StubsProperties `android:"arch_variant"` } type LibraryMutatedProperties struct { // Build a dylib variant BuildDylib bool `blueprint:"mutated"` // Build an rlib variant BuildRlib bool `blueprint:"mutated"` // Build a shared library variant BuildShared bool `blueprint:"mutated"` // Build a static library variant BuildStatic bool `blueprint:"mutated"` // This variant is a dylib VariantIsDylib bool `blueprint:"mutated"` // This variant is an rlib VariantIsRlib bool `blueprint:"mutated"` // This variant is a shared library VariantIsShared bool `blueprint:"mutated"` // This variant is a source provider VariantIsSource bool `blueprint:"mutated"` // This variant is disabled and should not be compiled // (used for SourceProvider variants that produce only source) VariantIsDisabled bool `blueprint:"mutated"` // Whether this library variant should be link libstd via rlibs VariantIsStaticStd bool `blueprint:"mutated"` // This variant is a stubs lib BuildStubs bool `blueprint:"mutated"` // This variant is the latest version IsLatestVersion bool `blueprint:"mutated"` // Version of the stubs lib StubsVersion string `blueprint:"mutated"` // List of all stubs versions associated with an implementation lib AllStubsVersions []string `blueprint:"mutated"` } type libraryDecorator struct { *baseCompiler *flagExporter stripper Stripper Properties LibraryCompilerProperties MutatedProperties LibraryMutatedProperties includeDirs android.Paths sourceProvider SourceProvider // table-of-contents file for cdylib crates to optimize out relinking when possible tocFile android.OptionalPath // Path to the file containing the APIs exported by this library stubsSymbolFilePath android.Path apiListCoverageXmlPath android.ModuleOutPath versionScriptPath android.OptionalPath } func (library *libraryDecorator) stubs() bool { return library.MutatedProperties.BuildStubs } func (library *libraryDecorator) setAPIListCoverageXMLPath(xml android.ModuleOutPath) { library.apiListCoverageXmlPath = xml } func (library *libraryDecorator) libraryProperties() LibraryCompilerProperties { return library.Properties } type libraryInterface interface { cc.VersionedInterface rlib() bool dylib() bool static() bool shared() bool sysroot() bool source() bool apexExclude() bool // Returns true if the build options for the module have selected a particular build type buildRlib() bool buildDylib() bool buildShared() bool buildStatic() bool // Sets a particular variant type setRlib() setDylib() setShared() setStatic() setSource() // libstd linkage functions rlibStd() bool setRlibStd() setDylibStd() // Build a specific library variant BuildOnlyFFI() BuildOnlyRust() BuildOnlyRlib() BuildOnlyDylib() BuildOnlyStatic() BuildOnlyShared() toc() android.OptionalPath IsStubsImplementationRequired() bool setAPIListCoverageXMLPath(out android.ModuleOutPath) libraryProperties() LibraryCompilerProperties } func (library *libraryDecorator) nativeCoverage() bool { if library.BuildStubs() { return false } return true } func (library *libraryDecorator) toc() android.OptionalPath { return library.tocFile } func (library *libraryDecorator) rlib() bool { return library.MutatedProperties.VariantIsRlib } func (library *libraryDecorator) sysroot() bool { return Bool(library.Properties.Sysroot) } func (library *libraryDecorator) dylib() bool { return library.MutatedProperties.VariantIsDylib } func (library *libraryDecorator) shared() bool { return library.MutatedProperties.VariantIsShared } func (library *libraryDecorator) static() bool { return false } func (library *libraryDecorator) source() bool { return library.MutatedProperties.VariantIsSource } func (library *libraryDecorator) apexExclude() bool { return Bool(library.Properties.Apex_exclude) } func (library *libraryDecorator) buildRlib() bool { return library.MutatedProperties.BuildRlib && BoolDefault(library.Properties.Rlib.Enabled, true) } func (library *libraryDecorator) buildDylib() bool { return library.MutatedProperties.BuildDylib && BoolDefault(library.Properties.Dylib.Enabled, true) } func (library *libraryDecorator) buildShared() bool { return library.MutatedProperties.BuildShared && BoolDefault(library.Properties.Shared.Enabled, true) } func (library *libraryDecorator) buildStatic() bool { return library.MutatedProperties.BuildStatic && BoolDefault(library.Properties.Static.Enabled, true) } func (library *libraryDecorator) setRlib() { library.MutatedProperties.VariantIsRlib = true library.MutatedProperties.VariantIsDylib = false library.MutatedProperties.VariantIsShared = false } func (library *libraryDecorator) setDylib() { library.MutatedProperties.VariantIsRlib = false library.MutatedProperties.VariantIsDylib = true library.MutatedProperties.VariantIsShared = false } func (library *libraryDecorator) rlibStd() bool { return library.MutatedProperties.VariantIsStaticStd } func (library *libraryDecorator) setRlibStd() { library.MutatedProperties.VariantIsStaticStd = true } func (library *libraryDecorator) setDylibStd() { library.MutatedProperties.VariantIsStaticStd = false } func (library *libraryDecorator) setShared() { library.MutatedProperties.VariantIsShared = true library.MutatedProperties.VariantIsRlib = false library.MutatedProperties.VariantIsDylib = false } func (library *libraryDecorator) setStatic() { panic(fmt.Errorf("static variant is not supported for rust modules, use the rlib variant instead")) } func (library *libraryDecorator) setSource() { library.MutatedProperties.VariantIsSource = true } func (library *libraryDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep { if library.preferRlib() { return rlibAutoDep } else if library.rlib() || library.static() { return rlibAutoDep } else if library.dylib() || library.shared() { return dylibAutoDep } else { panic(fmt.Errorf("autoDep called on library %q that has no enabled variants.", ctx.ModuleName())) } } func (library *libraryDecorator) stdLinkage(device bool) RustLinkage { if library.static() || library.MutatedProperties.VariantIsStaticStd { return RlibLinkage } else if library.baseCompiler.preferRlib() { return RlibLinkage } return DylibLinkage } var _ compiler = (*libraryDecorator)(nil) var _ libraryInterface = (*libraryDecorator)(nil) var _ cc.VersionedInterface = (*libraryDecorator)(nil) var _ exportedFlagsProducer = (*libraryDecorator)(nil) var _ cc.VersionedInterface = (*libraryDecorator)(nil) func (library *libraryDecorator) HasLLNDKStubs() bool { // Rust LLNDK is currently unsupported return false } func (library *libraryDecorator) HasVendorPublicLibrary() bool { // Rust does not support vendor_public_library yet. return false } func (library *libraryDecorator) HasLLNDKHeaders() bool { // Rust LLNDK is currently unsupported return false } func (library *libraryDecorator) HasStubsVariants() bool { // Just having stubs.symbol_file is enough to create a stub variant. In that case // the stub for the future API level is created. return library.Properties.Stubs.Symbol_file != nil || len(library.Properties.Stubs.Versions) > 0 } func (library *libraryDecorator) IsStubsImplementationRequired() bool { return BoolDefault(library.Properties.Stubs.Implementation_installable, true) } func (library *libraryDecorator) GetAPIListCoverageXMLPath() android.ModuleOutPath { return library.apiListCoverageXmlPath } func (library *libraryDecorator) AllStubsVersions() []string { return library.MutatedProperties.AllStubsVersions } func (library *libraryDecorator) SetAllStubsVersions(versions []string) { library.MutatedProperties.AllStubsVersions = versions } func (library *libraryDecorator) SetStubsVersion(version string) { library.MutatedProperties.StubsVersion = version } func (library *libraryDecorator) SetBuildStubs(isLatest bool) { library.MutatedProperties.BuildStubs = true library.MutatedProperties.IsLatestVersion = isLatest } func (library *libraryDecorator) BuildStubs() bool { return library.MutatedProperties.BuildStubs } func (library *libraryDecorator) ImplementationModuleName(name string) string { return name } func (library *libraryDecorator) IsLLNDKMovedToApex() bool { // Rust does not support LLNDK. return false } func (library *libraryDecorator) StubsVersion() string { return library.MutatedProperties.StubsVersion } // stubsVersions implements cc.VersionedInterface. func (library *libraryDecorator) StubsVersions(ctx android.BaseModuleContext) []string { if !library.HasStubsVariants() { return nil } // Future API level is implicitly added if there isn't versions := cc.AddCurrentVersionIfNotPresent(library.Properties.Stubs.Versions) cc.NormalizeVersions(ctx, versions) return versions } // rust_library produces all Rust variants (rust_library_dylib and // rust_library_rlib). func RustLibraryFactory() android.Module { module, library := NewRustLibrary(android.HostAndDeviceSupported) library.BuildOnlyRust() return module.Init() } // rust_ffi produces all FFI variants (rust_ffi_shared, rust_ffi_static). func RustFFIFactory() android.Module { module, library := NewRustLibrary(android.HostAndDeviceSupported) library.BuildOnlyFFI() return module.Init() } // rust_library_dylib produces a Rust dylib (Rust crate type "dylib"). func RustLibraryDylibFactory() android.Module { module, library := NewRustLibrary(android.HostAndDeviceSupported) library.BuildOnlyDylib() return module.Init() } // rust_library_rlib and rust_ffi_static produces an rlib (Rust crate type "rlib"). func RustLibraryRlibFactory() android.Module { module, library := NewRustLibrary(android.HostAndDeviceSupported) library.BuildOnlyRlib() return module.Init() } // rust_ffi_shared produces a shared library (Rust crate type // "cdylib"). func RustFFISharedFactory() android.Module { module, library := NewRustLibrary(android.HostAndDeviceSupported) library.BuildOnlyShared() 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 { module, library := NewRustLibrary(android.HostSupported) library.BuildOnlyRust() return module.Init() } // rust_ffi_host produces all FFI variants for the host // (rust_ffi_static_host and rust_ffi_shared_host). func RustFFIHostFactory() android.Module { module, library := NewRustLibrary(android.HostSupported) library.BuildOnlyFFI() return module.Init() } // rust_library_dylib_host produces a dylib for the host (Rust crate // type "dylib"). func RustLibraryDylibHostFactory() android.Module { module, library := NewRustLibrary(android.HostSupported) library.BuildOnlyDylib() return module.Init() } // rust_library_rlib_host and rust_ffi_static_host produces an rlib for the host // (Rust crate type "rlib"). func RustLibraryRlibHostFactory() android.Module { module, library := NewRustLibrary(android.HostSupported) library.BuildOnlyRlib() return module.Init() } // rust_ffi_shared_host produces an shared library for the host (Rust // crate type "cdylib"). func RustFFISharedHostFactory() android.Module { module, library := NewRustLibrary(android.HostSupported) library.BuildOnlyShared() return module.Init() } func CheckRustLibraryProperties(mctx android.DefaultableHookContext) { lib := mctx.Module().(*Module).compiler.(libraryInterface) if !lib.buildShared() { if lib.libraryProperties().Stubs.Symbol_file != nil || lib.libraryProperties().Stubs.Implementation_installable != nil || len(lib.libraryProperties().Stubs.Versions) > 0 { mctx.PropertyErrorf("stubs", "stubs properties can only be set for rust_ffi or rust_ffi_shared modules") } } } func (library *libraryDecorator) BuildOnlyFFI() { library.MutatedProperties.BuildDylib = false // we build rlibs for later static ffi linkage. library.MutatedProperties.BuildRlib = true library.MutatedProperties.BuildShared = true library.MutatedProperties.BuildStatic = false } func (library *libraryDecorator) BuildOnlyRust() { library.MutatedProperties.BuildDylib = true library.MutatedProperties.BuildRlib = true library.MutatedProperties.BuildShared = false library.MutatedProperties.BuildStatic = false } func (library *libraryDecorator) BuildOnlyDylib() { library.MutatedProperties.BuildDylib = true library.MutatedProperties.BuildRlib = false library.MutatedProperties.BuildShared = false library.MutatedProperties.BuildStatic = false } func (library *libraryDecorator) BuildOnlyRlib() { library.MutatedProperties.BuildDylib = false library.MutatedProperties.BuildRlib = true library.MutatedProperties.BuildShared = false library.MutatedProperties.BuildStatic = false } func (library *libraryDecorator) BuildOnlyStatic() { library.MutatedProperties.BuildRlib = false library.MutatedProperties.BuildDylib = false library.MutatedProperties.BuildShared = false library.MutatedProperties.BuildStatic = true } func (library *libraryDecorator) BuildOnlyShared() { library.MutatedProperties.BuildRlib = false library.MutatedProperties.BuildDylib = false library.MutatedProperties.BuildStatic = false library.MutatedProperties.BuildShared = true } func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) { module := newModule(hod, android.MultilibBoth) library := &libraryDecorator{ MutatedProperties: LibraryMutatedProperties{ BuildDylib: false, BuildRlib: false, BuildShared: false, BuildStatic: false, }, baseCompiler: NewBaseCompiler("lib", "lib64", InstallInSystem), flagExporter: NewFlagExporter(), } module.compiler = library module.SetDefaultableHook(CheckRustLibraryProperties) return module, library } func (library *libraryDecorator) compilerProps() []interface{} { return append(library.baseCompiler.compilerProps(), &library.Properties, &library.MutatedProperties, &library.stripper.StripProperties) } func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { deps = library.baseCompiler.compilerDeps(ctx, deps) if library.dylib() || library.shared() { if ctx.toolchain().Bionic() { deps = bionicDeps(ctx, deps, false) deps.CrtBegin = []string{"crtbegin_so"} deps.CrtEnd = []string{"crtend_so"} } else if ctx.Os() == android.LinuxMusl { deps = muslDeps(ctx, deps, false) deps.CrtBegin = []string{"libc_musl_crtbegin_so"} deps.CrtEnd = []string{"libc_musl_crtend_so"} } } return deps } func (library *libraryDecorator) sharedLibFilename(ctx ModuleContext) string { return library.getStem(ctx) + ctx.toolchain().SharedLibSuffix() } // Library cfg flags common to all variants func CommonLibraryCfgFlags(ctx android.ModuleContext, flags Flags) Flags { return flags } func (library *libraryDecorator) cfgFlags(ctx ModuleContext, flags Flags) Flags { flags = library.baseCompiler.cfgFlags(ctx, flags) flags = CommonLibraryCfgFlags(ctx, flags) cfgs := library.baseCompiler.Properties.Cfgs.GetOrDefault(ctx, nil) cfgFlags := cfgsToFlags(cfgs) flags.RustFlags = append(flags.RustFlags, cfgFlags...) flags.RustdocFlags = append(flags.RustdocFlags, cfgFlags...) return flags } // Common flags applied to all libraries irrespective of properties or variant should be included here func CommonLibraryCompilerFlags(ctx android.ModuleContext, flags Flags) Flags { flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName()) return flags } func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { flags = library.baseCompiler.compilerFlags(ctx, flags) flags = CommonLibraryCompilerFlags(ctx, flags) if library.rlib() || library.shared() { // rlibs collect include dirs as well since they are used to // produce staticlibs in the final C linkages 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( flags.LinkFlags, "-dynamic_lib", "-install_name @rpath/"+library.sharedLibFilename(ctx), ) } else { flags.LinkFlags = append(flags.LinkFlags, "-Wl,-soname="+library.sharedLibFilename(ctx)) } } return flags } func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput { var outputFile android.ModuleOutPath var ret buildOutput var fileName string crateRootPath := crateRootPath(ctx, library) if library.sourceProvider != nil { 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() outputFile = android.PathForModuleOut(ctx, fileName) ret.outputFile = outputFile } else if library.dylib() { fileName = library.getStem(ctx) + ctx.toolchain().DylibSuffix() outputFile = android.PathForModuleOut(ctx, fileName) ret.outputFile = outputFile } else if library.static() { fileName = library.getStem(ctx) + ctx.toolchain().StaticLibSuffix() outputFile = android.PathForModuleOut(ctx, fileName) ret.outputFile = outputFile } else if library.shared() { fileName = library.sharedLibFilename(ctx) outputFile = android.PathForModuleOut(ctx, fileName) ret.outputFile = outputFile } if !library.rlib() && !library.static() && library.stripper.NeedsStrip(ctx) { strippedOutputFile := outputFile outputFile = android.PathForModuleOut(ctx, "unstripped", fileName) library.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile) library.baseCompiler.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile) } library.baseCompiler.unstrippedOutputFile = outputFile flags.RustFlags = append(flags.RustFlags, deps.depFlags...) flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...) flags.LinkFlags = append(flags.LinkFlags, deps.rustLibObjects...) flags.LinkFlags = append(flags.LinkFlags, deps.sharedLibObjects...) flags.LinkFlags = append(flags.LinkFlags, deps.staticLibObjects...) flags.LinkFlags = append(flags.LinkFlags, deps.wholeStaticLibObjects...) if String(library.Properties.Version_script) != "" { if String(library.Properties.Extra_exported_symbols) != "" { ctx.ModuleErrorf("version_script and extra_exported_symbols cannot both be set.") } if library.shared() { // "-Wl,--android-version-script" signals to the rustcLinker script // that the default version script should be removed. flags.LinkFlags = append(flags.LinkFlags, "-Wl,--android-version-script="+android.PathForModuleSrc(ctx, String(library.Properties.Version_script)).String()) deps.LinkerDeps = append(deps.LinkerDeps, android.PathForModuleSrc(ctx, String(library.Properties.Version_script))) } else if !library.static() && !library.rlib() { // We include rlibs here because rust_ffi produces rlib variants ctx.PropertyErrorf("version_script", "can only be set for rust_ffi modules") } } if String(library.Properties.Extra_exported_symbols) != "" { // Passing a second version script (rustc calculates and emits a // default version script) will concatenate the first version script. flags.LinkFlags = append(flags.LinkFlags, "-Wl,--version-script="+android.PathForModuleSrc(ctx, String(library.Properties.Extra_exported_symbols)).String()) deps.LinkerDeps = append(deps.LinkerDeps, android.PathForModuleSrc(ctx, String(library.Properties.Extra_exported_symbols))) } if library.dylib() { // We need prefer-dynamic for now to avoid linking in the static stdlib. See: // https://github.com/rust-lang/rust/issues/19680 // https://github.com/rust-lang/rust/issues/34909 flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic") } // Call the appropriate builder for this library type if library.stubs() { ccFlags := library.getApiStubsCcFlags(ctx) stubObjs := library.compileModuleLibApiStubs(ctx, ccFlags) cc.BuildRustStubs(ctx, outputFile, stubObjs, ccFlags) } else if library.rlib() { ret.kytheFile = TransformSrctoRlib(ctx, crateRootPath, deps, flags, outputFile).kytheFile } else if library.dylib() { ret.kytheFile = TransformSrctoDylib(ctx, crateRootPath, deps, flags, outputFile).kytheFile } else if library.static() { ret.kytheFile = TransformSrctoStatic(ctx, crateRootPath, deps, flags, outputFile).kytheFile } else if library.shared() { ret.kytheFile = TransformSrctoShared(ctx, crateRootPath, deps, flags, outputFile).kytheFile } // rlibs and dylibs propagate their shared, whole static, and rustlib dependencies if library.rlib() || library.dylib() { library.flagExporter.exportLinkDirs(deps.linkDirs...) library.flagExporter.exportRustLibs(deps.rustLibObjects...) library.flagExporter.exportSharedLibs(deps.sharedLibObjects...) library.flagExporter.exportWholeStaticLibs(deps.wholeStaticLibObjects...) } // rlibs also propagate their staticlibs dependencies if library.rlib() { library.flagExporter.exportStaticLibs(deps.staticLibObjects...) } // Since we have FFI rlibs, we need to collect their includes as well if library.static() || library.shared() || library.rlib() || library.stubs() { ccExporter := cc.FlagExporterInfo{ IncludeDirs: android.FirstUniquePaths(library.includeDirs), } if library.rlib() { ccExporter.RustRlibDeps = append(ccExporter.RustRlibDeps, deps.reexportedCcRlibDeps...) ccExporter.RustRlibDeps = append(ccExporter.RustRlibDeps, deps.reexportedWholeCcRlibDeps...) } android.SetProvider(ctx, cc.FlagExporterInfoProvider, ccExporter) } if library.dylib() { // reexport whole-static'd dependencies for dylibs. library.flagExporter.wholeRustRlibDeps = append(library.flagExporter.wholeRustRlibDeps, deps.reexportedWholeCcRlibDeps...) } if library.shared() || library.stubs() { // Optimize out relinking against shared libraries whose interface hasn't changed by // depending on a table of contents file instead of the library itself. tocFile := outputFile.ReplaceExtension(ctx, flags.Toolchain.SharedLibSuffix()[1:]+".toc") library.tocFile = android.OptionalPathForPath(tocFile) cc.TransformSharedObjectToToc(ctx, outputFile, tocFile) android.SetProvider(ctx, cc.SharedLibraryInfoProvider, cc.SharedLibraryInfo{ TableOfContents: android.OptionalPathForPath(tocFile), SharedLibrary: outputFile, Target: ctx.Target(), IsStubs: library.BuildStubs(), }) } if library.static() { depSet := depset.NewBuilder[android.Path](depset.TOPOLOGICAL).Direct(outputFile).Build() android.SetProvider(ctx, cc.StaticLibraryInfoProvider, cc.StaticLibraryInfo{ StaticLibrary: outputFile, TransitiveStaticLibrariesForOrdering: depSet, }) } cc.AddStubDependencyProviders(ctx) // Set our flagexporter provider to export relevant Rust flags library.flagExporter.setRustProvider(ctx) return ret } func (library *libraryDecorator) checkedCrateRootPath() (android.Path, error) { if library.sourceProvider != nil { srcs := library.sourceProvider.Srcs() if len(srcs) == 0 { return nil, errors.New("Source provider generated 0 sources") } // Assume the first source from the source provider is the library entry point. return srcs[0], nil } else { return library.baseCompiler.checkedCrateRootPath() } } func (library *libraryDecorator) getApiStubsCcFlags(ctx ModuleContext) cc.Flags { ccFlags := cc.Flags{} toolchain := cc_config.FindToolchain(ctx.Os(), ctx.Arch()) platformSdkVersion := "" if ctx.Device() { platformSdkVersion = ctx.Config().PlatformSdkVersion().String() } minSdkVersion := cc.MinSdkVersion(ctx.RustModule(), cc.CtxIsForPlatform(ctx), ctx.Device(), platformSdkVersion) // Collect common CC compilation flags ccFlags = cc.CommonLinkerFlags(ctx, ccFlags, true, toolchain, false) ccFlags = cc.CommonLibraryLinkerFlags(ctx, ccFlags, toolchain, library.getStem(ctx)) ccFlags = cc.AddStubLibraryCompilerFlags(ccFlags) ccFlags = cc.AddTargetFlags(ctx, ccFlags, toolchain, minSdkVersion, false) return ccFlags } func (library *libraryDecorator) compileModuleLibApiStubs(ctx ModuleContext, ccFlags cc.Flags) cc.Objects { mod := ctx.RustModule() symbolFile := String(library.Properties.Stubs.Symbol_file) library.stubsSymbolFilePath = android.PathForModuleSrc(ctx, symbolFile) apiParams := cc.ApiStubsParams{ NotInPlatform: mod.NotInPlatform(), IsNdk: mod.IsNdk(ctx.Config()), BaseModuleName: mod.BaseModuleName(), ModuleName: ctx.ModuleName(), } flag := cc.GetApiStubsFlags(apiParams) nativeAbiResult := cc.ParseNativeAbiDefinition(ctx, symbolFile, android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), flag) objs := cc.CompileStubLibrary(ctx, ccFlags, nativeAbiResult.StubSrc, mod.getSharedFlags()) library.versionScriptPath = android.OptionalPathForPath(nativeAbiResult.VersionScript) // Parse symbol file to get API list for coverage if library.StubsVersion() == "current" && ctx.PrimaryArch() && !mod.InRecovery() && !mod.InProduct() && !mod.InVendor() { library.apiListCoverageXmlPath = cc.ParseSymbolFileForAPICoverage(ctx, symbolFile) } return objs } func (library *libraryDecorator) rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath { // rustdoc has builtin support for documenting config specific information // regardless of the actual config it was given // (https://doc.rust-lang.org/rustdoc/advanced-features.html#cfgdoc-documenting-platform-specific-or-feature-specific-information), // so we generate the rustdoc for only the primary module so that we have a // single set of docs to refer to. if ctx.Module() != ctx.PrimaryModule() { return android.OptionalPath{} } return android.OptionalPathForPath(Rustdoc(ctx, crateRootPath(ctx, library), deps, flags)) } func (library *libraryDecorator) getStem(ctx ModuleContext) string { stem := library.baseCompiler.getStemWithoutSuffix(ctx) validateLibraryStem(ctx, stem, library.crateName()) return stem + String(library.baseCompiler.Properties.Suffix) } func (library *libraryDecorator) install(ctx ModuleContext) { // Only shared and dylib variants make sense to install. if library.shared() || library.dylib() { library.baseCompiler.install(ctx) } } func (library *libraryDecorator) Disabled() bool { return library.MutatedProperties.VariantIsDisabled } func (library *libraryDecorator) SetDisabled() { library.MutatedProperties.VariantIsDisabled = true } func (library *libraryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { library.baseCompiler.moduleInfoJSON(ctx, moduleInfoJSON) if library.rlib() { moduleInfoJSON.Class = []string{"RLIB_LIBRARIES"} } else if library.dylib() { moduleInfoJSON.Class = []string{"DYLIB_LIBRARIES"} } else if library.static() { moduleInfoJSON.Class = []string{"STATIC_LIBRARIES"} } else if library.shared() { moduleInfoJSON.Class = []string{"SHARED_LIBRARIES"} } } var validCrateName = regexp.MustCompile("[^a-zA-Z0-9_]+") func validateLibraryStem(ctx BaseModuleContext, filename string, crate_name string) { if crate_name == "" { ctx.PropertyErrorf("crate_name", "crate_name must be defined.") } // crate_names are used for the library output file, and rustc expects these // to be alphanumeric with underscores allowed. if validCrateName.MatchString(crate_name) { ctx.PropertyErrorf("crate_name", "library crate_names must be alphanumeric with underscores allowed") } // Libraries are expected to begin with "lib" followed by the crate_name if !strings.HasPrefix(filename, "lib"+crate_name) { ctx.ModuleErrorf("Invalid name or stem property; library filenames must start with lib") } } type libraryTransitionMutator struct{} func (libraryTransitionMutator) Split(ctx android.BaseModuleContext) []string { m, ok := ctx.Module().(*Module) if !ok || m.compiler == nil { return []string{""} } library, ok := m.compiler.(libraryInterface) if !ok { return []string{""} } // Don't produce rlib/dylib/source variants for shared or static variants if library.shared() || library.static() { return []string{""} } 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. if m.sourceProvider != nil { variants = append(variants, sourceVariation) } if library.buildRlib() { variants = append(variants, rlibVariation) } if library.buildDylib() { variants = append(variants, dylibVariation) } if len(variants) == 0 { return []string{""} } return variants } func (libraryTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { if ctx.DepTag() == android.PrebuiltDepTag { return sourceVariation } return "" } func (libraryTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { m, ok := ctx.Module().(*Module) if !ok || m.compiler == nil { return "" } library, ok := m.compiler.(libraryInterface) if !ok { return "" } if incomingVariation == "" { if m.sourceProvider != nil { return sourceVariation } if library.shared() { return "" } if library.buildRlib() { return rlibVariation } if library.buildDylib() { return dylibVariation } } return incomingVariation } func (libraryTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { m, ok := ctx.Module().(*Module) if !ok || m.compiler == nil { return } library, ok := m.compiler.(libraryInterface) if !ok { return } switch variation { case rlibVariation: library.setRlib() case dylibVariation: library.setDylib() if m.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation { // TODO(b/165791368) // Disable dylib Vendor Ramdisk variations until we support these. m.Disable() } case sourceVariation: library.setSource() // The source variant does not produce any library. // Disable the compilation steps. m.compiler.SetDisabled() } // If a source variant is created, add an inter-variant dependency // between the other variants and the source variant. if m.sourceProvider != nil && variation != sourceVariation { ctx.AddVariationDependencies( []blueprint.Variation{ {"rust_libraries", sourceVariation}, }, sourceDepTag, ctx.ModuleName()) } if prebuilt, ok := m.compiler.(*prebuiltLibraryDecorator); ok { if Bool(prebuilt.Properties.Force_use_prebuilt) && len(prebuilt.prebuiltSrcs()) > 0 { m.Prebuilt().SetUsePrebuilt(true) } } } type libstdTransitionMutator struct{} func (libstdTransitionMutator) Split(ctx android.BaseModuleContext) []string { if m, ok := ctx.Module().(*Module); ok && m.compiler != nil && !m.compiler.Disabled() { // Only create a variant if a library is actually being built. if library, ok := m.compiler.(libraryInterface); ok { if library.rlib() && !library.sysroot() { return []string{"rlib-std", "dylib-std"} } } } return []string{""} } func (libstdTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { if ctx.DepTag() == android.PrebuiltDepTag { return sourceVariation } return "" } func (libstdTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { if m, ok := ctx.Module().(*Module); ok && m.compiler != nil && !m.compiler.Disabled() { if library, ok := m.compiler.(libraryInterface); ok { if library.shared() { return "" } if library.rlib() && !library.sysroot() { if incomingVariation != "" { return incomingVariation } return "rlib-std" } } } return "" } func (libstdTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { if variation == "rlib-std" { rlib := ctx.Module().(*Module) rlib.compiler.(libraryInterface).setRlibStd() rlib.Properties.RustSubName += RlibStdlibSuffix } else if variation == "dylib-std" { dylib := ctx.Module().(*Module) 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() } } }