CcApiLibrary Variants for LLNDK
Define CcApiLibrary Variants for LLNDK. Each variant will be defined as
below.
cc_api_variant {
name: "libc",
variant: "llndk",
arch: {
x86_64: {
src: "libs/x86_64/libc.so",
},
...
},
}
And CcApiLibrary will be marked to use this variant as below.
cc_api_library {
name: "libc",
...
variants: [
"llndk",
...
]
}
Soong will replace source of libc cc_api_library as src from
cc_api_variant during build time.
Bug: 244244438
Test: cf vendor build succeeded with LLNDK variants
Change-Id: I317ed1f558beb1f82f9f2d70811fa8f765bcad2b
diff --git a/cc/cc.go b/cc/cc.go
index a8011b8..8840631 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -2540,6 +2540,8 @@
}, vndkExtDepTag, GetReplaceModuleName(vndkdep.getVndkExtendsModuleName(), GetSnapshot(c, &snapshotInfo, actx).SharedLibs))
}
}
+
+ updateImportedLibraryDependency(ctx)
}
func BeginMutator(ctx android.BottomUpMutatorContext) {
diff --git a/cc/library.go b/cc/library.go
index 41a68e3..aefb804 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -2597,11 +2597,12 @@
m := mctx.Module().(*Module)
isLLNDK := m.IsLlndk()
isVendorPublicLibrary := m.IsVendorPublicLibrary()
+ isImportedApiLibrary := m.isImportedApiLibrary()
modules := mctx.CreateLocalVariations(variants...)
for i, m := range modules {
- if variants[i] != "" || isLLNDK || isVendorPublicLibrary {
+ if variants[i] != "" || isLLNDK || isVendorPublicLibrary || isImportedApiLibrary {
// A stubs or LLNDK stubs variant.
c := m.(*Module)
c.sanitize = nil
diff --git a/cc/library_stub.go b/cc/library_stub.go
index 760d36a..2fb21a3 100644
--- a/cc/library_stub.go
+++ b/cc/library_stub.go
@@ -15,6 +15,10 @@
package cc
import (
+ "strings"
+
+ "github.com/google/blueprint/proptools"
+
"android/soong/android"
"android/soong/multitree"
)
@@ -26,6 +30,30 @@
func RegisterLibraryStubBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("cc_api_library", CcApiLibraryFactory)
ctx.RegisterModuleType("cc_api_headers", CcApiHeadersFactory)
+ ctx.RegisterModuleType("cc_api_variant", CcApiVariantFactory)
+}
+
+func updateImportedLibraryDependency(ctx android.BottomUpMutatorContext) {
+ m, ok := ctx.Module().(*Module)
+ if !ok {
+ return
+ }
+
+ apiLibrary, ok := m.linker.(*apiLibraryDecorator)
+ if !ok {
+ return
+ }
+
+ if m.UseVndk() && apiLibrary.hasLLNDKStubs() {
+ // Add LLNDK dependencies
+ for _, variant := range apiLibrary.properties.Variants {
+ if variant == "llndk" {
+ variantName := BuildApiVariantName(m.BaseModuleName(), "llndk", "")
+ ctx.AddDependency(m, nil, variantName)
+ break
+ }
+ }
+ }
}
// 'cc_api_library' is a module type which is from the exported API surface
@@ -33,7 +61,8 @@
// offer a link to the module that generates shared library object from the
// map file.
type apiLibraryProperties struct {
- Src *string `android:"arch_variant"`
+ Src *string `android:"arch_variant"`
+ Variants []string
}
type apiLibraryDecorator struct {
@@ -55,11 +84,9 @@
module.compiler = nil
module.linker = apiLibraryDecorator
module.installer = nil
+ module.library = apiLibraryDecorator
module.AddProperties(&module.Properties, &apiLibraryDecorator.properties)
- // Mark module as stub, so APEX would not include this stub in the package.
- module.library.setBuildStubs(true)
-
// Prevent default system libs (libc, libm, and libdl) from being linked
if apiLibraryDecorator.baseLinker.Properties.System_shared_libs == nil {
apiLibraryDecorator.baseLinker.Properties.System_shared_libs = []string{}
@@ -91,12 +118,45 @@
}
func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objects Objects) android.Path {
- // Export headers as system include dirs if specified. Mostly for libc
- if Bool(d.libraryDecorator.Properties.Llndk.Export_headers_as_system) {
- d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs = append(
- d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs,
- d.libraryDecorator.flagExporter.Properties.Export_include_dirs...)
- d.libraryDecorator.flagExporter.Properties.Export_include_dirs = nil
+ m, _ := ctx.Module().(*Module)
+
+ var in android.Path
+
+ if src := proptools.String(d.properties.Src); src != "" {
+ in = android.PathForModuleSrc(ctx, src)
+ }
+
+ // LLNDK variant
+ if m.UseVndk() && d.hasLLNDKStubs() {
+ apiVariantModule := BuildApiVariantName(m.BaseModuleName(), "llndk", "")
+
+ var mod android.Module
+
+ ctx.VisitDirectDeps(func(depMod android.Module) {
+ if depMod.Name() == apiVariantModule {
+ mod = depMod
+ }
+ })
+
+ if mod != nil {
+ variantMod, ok := mod.(*CcApiVariant)
+ if ok {
+ in = variantMod.Src()
+
+ // Copy LLDNK properties to cc_api_library module
+ d.libraryDecorator.flagExporter.Properties.Export_include_dirs = append(
+ d.libraryDecorator.flagExporter.Properties.Export_include_dirs,
+ variantMod.exportProperties.Export_headers...)
+
+ // Export headers as system include dirs if specified. Mostly for libc
+ if proptools.Bool(variantMod.exportProperties.Export_headers_as_system) {
+ d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs = append(
+ d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs,
+ d.libraryDecorator.flagExporter.Properties.Export_include_dirs...)
+ d.libraryDecorator.flagExporter.Properties.Export_include_dirs = nil
+ }
+ }
+ }
}
// Flags reexported from dependencies. (e.g. vndk_prebuilt_shared)
@@ -107,13 +167,10 @@
d.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
d.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
- if d.properties.Src == nil {
- ctx.PropertyErrorf("src", "src is a required property")
+ if in == nil {
+ ctx.PropertyErrorf("src", "Unable to locate source property")
+ return nil
}
- // Skip the existence check of the stub prebuilt file.
- // The file is not guaranteed to exist during Soong analysis.
- // Build orchestrator will be responsible for creating a connected ninja graph.
- in := android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), *d.properties.Src)
// Make the _compilation_ of rdeps have an order-only dep on cc_api_library.src (an .so file)
// The .so file itself has an order-only dependency on the headers contributed by this library.
@@ -143,6 +200,43 @@
return true
}
+func (d *apiLibraryDecorator) stubsVersions(ctx android.BaseMutatorContext) []string {
+ m, ok := ctx.Module().(*Module)
+
+ if !ok {
+ return nil
+ }
+
+ if d.hasLLNDKStubs() && m.UseVndk() {
+ // LLNDK libraries only need a single stubs variant.
+ return []string{android.FutureApiLevel.String()}
+ }
+
+ // TODO(b/244244438) Create more version information for NDK and APEX variations
+ // NDK variants
+ if m.MinSdkVersion() == "" {
+ return nil
+ }
+
+ firstVersion, err := nativeApiLevelFromUser(ctx,
+ m.MinSdkVersion())
+
+ if err != nil {
+ return nil
+ }
+
+ return ndkLibraryVersions(ctx, firstVersion)
+}
+
+func (d *apiLibraryDecorator) hasLLNDKStubs() bool {
+ for _, variant := range d.properties.Variants {
+ if strings.Contains(variant, "llndk") {
+ return true
+ }
+ }
+ return false
+}
+
// 'cc_api_headers' is similar with 'cc_api_library', but which replaces
// header libraries. The module will replace any dependencies to existing
// original header libraries.
@@ -165,9 +259,6 @@
module.linker = apiHeadersDecorator
module.installer = nil
- // Mark module as stub, so APEX would not include this stub in the package.
- module.library.setBuildStubs(true)
-
// Prevent default system libs (libc, libm, and libdl) from being linked
if apiHeadersDecorator.baseLinker.Properties.System_shared_libs == nil {
apiHeadersDecorator.baseLinker.Properties.System_shared_libs = []string{}
@@ -189,3 +280,91 @@
// Stub from API surface should be available for any APEX.
return true
}
+
+type ccApiexportProperties struct {
+ Src *string `android:"arch_variant"`
+ Variant *string
+ Version *string
+}
+
+type variantExporterProperties struct {
+ // Header directory or library to export
+ Export_headers []string
+
+ // Export all headers as system include
+ Export_headers_as_system *bool
+}
+
+type CcApiVariant struct {
+ android.ModuleBase
+
+ properties ccApiexportProperties
+ exportProperties variantExporterProperties
+
+ src android.Path
+}
+
+var _ android.Module = (*CcApiVariant)(nil)
+var _ android.ImageInterface = (*CcApiVariant)(nil)
+
+func CcApiVariantFactory() android.Module {
+ module := &CcApiVariant{}
+
+ module.AddProperties(&module.properties)
+ module.AddProperties(&module.exportProperties)
+
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
+ return module
+}
+
+func (v *CcApiVariant) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // No need to build
+
+ if proptools.String(v.properties.Src) == "" {
+ ctx.PropertyErrorf("src", "src is a required property")
+ }
+
+ // Skip the existence check of the stub prebuilt file.
+ // The file is not guaranteed to exist during Soong analysis.
+ // Build orchestrator will be responsible for creating a connected ninja graph.
+ v.src = android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), proptools.String(v.properties.Src))
+}
+
+func (v *CcApiVariant) Name() string {
+ version := proptools.String(v.properties.Version)
+ return BuildApiVariantName(v.BaseModuleName(), *v.properties.Variant, version)
+}
+
+func (v *CcApiVariant) Src() android.Path {
+ return v.src
+}
+
+func BuildApiVariantName(baseName string, variant string, version string) string {
+ names := []string{baseName, variant}
+ if version != "" {
+ names = append(names, version)
+ }
+
+ return strings.Join(names[:], ".") + multitree.GetApiImportSuffix()
+}
+
+// Implement ImageInterface to generate image variants
+func (v *CcApiVariant) ImageMutatorBegin(ctx android.BaseModuleContext) {}
+func (v *CcApiVariant) CoreVariantNeeded(ctx android.BaseModuleContext) bool { return false }
+func (v *CcApiVariant) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false }
+func (v *CcApiVariant) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false }
+func (v *CcApiVariant) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false }
+func (v *CcApiVariant) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { return false }
+func (v *CcApiVariant) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+ var variations []string
+ platformVndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
+
+ if proptools.String(v.properties.Variant) == "llndk" {
+ variations = append(variations, VendorVariationPrefix+platformVndkVersion)
+ variations = append(variations, ProductVariationPrefix+platformVndkVersion)
+ }
+
+ return variations
+}
+func (v *CcApiVariant) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
+}
diff --git a/cc/library_stub_test.go b/cc/library_stub_test.go
index 54b0ba6..8ce74c4 100644
--- a/cc/library_stub_test.go
+++ b/cc/library_stub_test.go
@@ -284,3 +284,54 @@
// These header files are required for compiling the other API domain (vendor in this case)
android.AssertStringListContains(t, "Vendor binary compilation should have an implicit dep on the stub .so file", vendorImplicits, "libfoo.so")
}
+
+func TestApiLibraryWithLlndkVariant(t *testing.T) {
+ bp := `
+ cc_binary {
+ name: "binfoo",
+ vendor: true,
+ srcs: ["binfoo.cc"],
+ shared_libs: ["libbar"],
+ }
+
+ cc_api_library {
+ name: "libbar",
+ // TODO(b/244244438) Remove src property once all variants are implemented.
+ src: "libbar.so",
+ vendor_available: true,
+ variants: [
+ "llndk",
+ ],
+ }
+
+ cc_api_variant {
+ name: "libbar",
+ variant: "llndk",
+ src: "libbar_llndk.so",
+ export_headers: ["libbar_llndk_include"]
+ }
+
+ api_imports {
+ name: "api_imports",
+ shared_libs: [
+ "libbar",
+ ],
+ header_libs: [],
+ }
+ `
+
+ ctx := prepareForCcTest.RunTestWithBp(t, bp)
+
+ libfoo := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Module()
+ libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module()
+ libbarApiVariant := ctx.ModuleForTests("libbar.llndk.apiimport", "android_vendor.29_arm64_armv8-a").Module()
+
+ android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
+ android.AssertBoolEquals(t, "Stub library variant from API surface should be linked", true, hasDirectDependency(t, ctx, libbarApiImport, libbarApiVariant))
+
+ libFooLibFlags := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Rule("ld").Args["libFlags"]
+ android.AssertStringDoesContain(t, "Vendor binary should be linked with LLNDK variant source", libFooLibFlags, "libbar_llndk.so")
+
+ libFooCFlags := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Rule("cc").Args["cFlags"]
+ android.AssertStringDoesContain(t, "Vendor binary should include headers from the LLNDK variant source", libFooCFlags, "-Ilibbar_llndk_include")
+}
diff --git a/cc/sdk.go b/cc/sdk.go
index a83e5ad..a0d196b 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -78,5 +78,7 @@
}
case *snapshotModule:
ctx.CreateVariations("")
+ case *CcApiVariant:
+ ctx.CreateVariations("")
}
}