summaryrefslogtreecommitdiff
path: root/rust/library.go
diff options
context:
space:
mode:
author Ivan Lozano <ivanlozano@google.com> 2024-10-30 18:15:59 +0000
committer Ivan Lozano <ivanlozano@google.com> 2025-01-10 21:47:09 +0000
commita8a1fa1096240ee059c30cad9828ea0f9d0c161d (patch)
treeb1b0c415516720e5df8cd87eaff6aa97801eee02 /rust/library.go
parent9587f45b194ad3f1a4676a7f5d24acce03efc204 (diff)
rust: Add stub support for rust_ffi modules
This adds stubs support for rust_ffi and rust_ffi_shared modules. Usage should match current cc usage. The stubs generator leveraged is the cc stubs generator. Bug: 203478530 Test: m blueprint_tests Change-Id: I043b9714a357cd5fe17c183ccdf86900f5172e0e
Diffstat (limited to 'rust/library.go')
-rw-r--r--rust/library.go162
1 files changed, 138 insertions, 24 deletions
diff --git a/rust/library.go b/rust/library.go
index 9912c946e..49169ac08 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,6 +194,11 @@ type libraryInterface interface {
BuildOnlyShared()
toc() android.OptionalPath
+
+ IsStubsImplementationRequired() bool
+ setAPIListCoverageXMLPath(out android.ModuleOutPath)
+
+ libraryProperties() LibraryCompilerProperties
}
func (library *libraryDecorator) nativeCoverage() bool {
@@ -276,58 +314,63 @@ 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 does not support LLNDK yet.
+ // Rust LLNDK is currently unsupported
return false
}
func (library *libraryDecorator) HasVendorPublicLibrary() bool {
- // Rust does not support vendor public library.
+ // Rust does not support vendor_public_library yet.
return false
}
func (library *libraryDecorator) HasLLNDKHeaders() bool {
- // Rust does not support LLNDK yet.
+ // Rust LLNDK is currently unsupported
return false
}
func (library *libraryDecorator) HasStubsVariants() bool {
- return false
+ // 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 false
+ return BoolDefault(library.Properties.Stubs.Implementation_installable, true)
}
func (library *libraryDecorator) GetAPIListCoverageXMLPath() android.ModuleOutPath {
- panic(fmt.Errorf("GetAPIListCoverageXMLPath called on unsupported Rust module"))
+ return library.apiListCoverageXmlPath
}
func (library *libraryDecorator) AllStubsVersions() []string {
- panic(fmt.Errorf("AllStubsVersions called on unsupported Rust module"))
+ return library.MutatedProperties.AllStubsVersions
}
func (library *libraryDecorator) SetAllStubsVersions(versions []string) {
- panic(fmt.Errorf("ApexSdkVersion called on unsupported Rust module"))
+ library.MutatedProperties.AllStubsVersions = versions
}
func (library *libraryDecorator) SetStubsVersion(version string) {
- panic(fmt.Errorf("SetStubsVersion called on unsupported Rust module"))
+ library.MutatedProperties.StubsVersion = version
}
func (library *libraryDecorator) SetBuildStubs(isLatest bool) {
- panic(fmt.Errorf("SetBuildStubs called on unsupported Rust module"))
+ library.MutatedProperties.BuildStubs = true
+ library.MutatedProperties.IsLatestVersion = isLatest
}
func (library *libraryDecorator) BuildStubs() bool {
- return false
+ return library.MutatedProperties.BuildStubs
}
func (library *libraryDecorator) ImplementationModuleName(name string) string {
- panic(fmt.Errorf("ImplementationModuleName called on unsupported Rust module"))
+ return name
}
func (library *libraryDecorator) IsLLNDKMovedToApex() bool {
@@ -335,12 +378,20 @@ func (library *libraryDecorator) IsLLNDKMovedToApex() bool {
return false
}
-func (library *libraryDecorator) StubsVersions(ctx android.BaseModuleContext) []string {
- panic(fmt.Errorf("StubsVersions called on unsupported Rust module"))
+func (library *libraryDecorator) StubsVersion() string {
+ return library.MutatedProperties.StubsVersion
}
-func (library *libraryDecorator) StubsVersion() string {
- panic(fmt.Errorf("StubsVersions called on unsupported Rust module"))
+// 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
@@ -420,6 +471,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.
@@ -479,6 +542,7 @@ func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorat
module.compiler = library
+ module.SetDefaultableHook(CheckRustLibraryProperties)
return module, library
}
@@ -641,7 +705,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, deps.CrtBegin, deps.CrtEnd, 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
@@ -657,13 +725,13 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa
}
// Since we have FFI rlibs, we need to collect their includes as well
- if library.static() || library.shared() || library.rlib() {
+ if library.static() || library.shared() || library.rlib() || library.stubs() {
android.SetProvider(ctx, cc.FlagExporterInfoProvider, cc.FlagExporterInfo{
IncludeDirs: android.FirstUniquePaths(library.includeDirs),
})
}
- if library.shared() {
+ 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")
@@ -674,9 +742,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(),
})
}
@@ -688,6 +754,7 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa
TransitiveStaticLibrariesForOrdering: depSet,
})
}
+ cc.AddStubDependencyProviders(ctx)
library.flagExporter.setProvider(ctx)
@@ -707,6 +774,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