summaryrefslogtreecommitdiff
path: root/rust/library.go
diff options
context:
space:
mode:
Diffstat (limited to 'rust/library.go')
-rw-r--r--rust/library.go255
1 files changed, 242 insertions, 13 deletions
diff --git a/rust/library.go b/rust/library.go
index 2d62dcfe4..415785a16 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -25,6 +25,7 @@ import (
"android/soong/android"
"android/soong/cc"
+ cc_config "android/soong/cc/config"
)
var (
@@ -79,9 +80,13 @@ type LibraryCompilerProperties struct {
// Whether this library is part of the Rust toolchain sysroot.
Sysroot *bool
- // Exclude this rust_ffi target from being included in APEXes.
- // TODO(b/362509506): remove this once stubs are properly supported by rust_ffi targets.
+ // 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 {
@@ -109,6 +114,15 @@ type LibraryMutatedProperties struct {
// 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 {
@@ -123,9 +137,28 @@ type libraryDecorator struct {
// 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
@@ -161,9 +194,17 @@ type libraryInterface interface {
BuildOnlyShared()
toc() android.OptionalPath
+
+ IsStubsImplementationRequired() bool
+ setAPIListCoverageXMLPath(out android.ModuleOutPath)
+
+ libraryProperties() LibraryCompilerProperties
}
func (library *libraryDecorator) nativeCoverage() bool {
+ if library.BuildStubs() {
+ return false
+ }
return true
}
@@ -276,7 +317,85 @@ func (library *libraryDecorator) stdLinkage(device bool) RustLinkage {
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).
@@ -355,6 +474,18 @@ func RustFFISharedHostFactory() android.Module {
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.
@@ -414,6 +545,7 @@ func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorat
module.compiler = library
+ module.SetDefaultableHook(CheckRustLibraryProperties)
return module, library
}
@@ -542,7 +674,10 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa
flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
- flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
+ 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) != "" {
@@ -576,7 +711,11 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa
}
// Call the appropriate builder for this library type
- if library.rlib() {
+ 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
@@ -586,19 +725,36 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa
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.exportLinkObjects(deps.linkObjects...)
+ 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() {
- android.SetProvider(ctx, cc.FlagExporterInfoProvider, cc.FlagExporterInfo{
+ 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.shared() {
+ 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")
@@ -609,9 +765,7 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa
TableOfContents: android.OptionalPathForPath(tocFile),
SharedLibrary: outputFile,
Target: ctx.Target(),
- // TODO: when rust supports stubs uses the stubs state rather than inferring it from
- // apex_exclude.
- IsStubs: Bool(library.Properties.Apex_exclude),
+ IsStubs: library.BuildStubs(),
})
}
@@ -623,8 +777,10 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa
TransitiveStaticLibrariesForOrdering: depSet,
})
}
+ cc.AddStubDependencyProviders(ctx)
- library.flagExporter.setProvider(ctx)
+ // Set our flagexporter provider to export relevant Rust flags
+ library.flagExporter.setRustProvider(ctx)
return ret
}
@@ -642,6 +798,53 @@ func (library *libraryDecorator) checkedCrateRootPath() (android.Path, error) {
}
}
+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
@@ -679,6 +882,20 @@ 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) {
@@ -737,6 +954,9 @@ func (libraryTransitionMutator) Split(ctx android.BaseModuleContext) []string {
}
func (libraryTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+ if ctx.DepTag() == android.PrebuiltDepTag {
+ return sourceVariation
+ }
return ""
}
@@ -804,6 +1024,12 @@ func (libraryTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, varia
},
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{}
@@ -821,6 +1047,9 @@ func (libstdTransitionMutator) Split(ctx android.BaseModuleContext) []string {
}
func (libstdTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+ if ctx.DepTag() == android.PrebuiltDepTag {
+ return sourceVariation
+ }
return ""
}