Merge "Support NDK variant of cc_api_variant"

This commit is contained in:
Kiyoung Kim
2022-12-01 02:45:33 +00:00
committed by Gerrit Code Review
4 changed files with 340 additions and 48 deletions

View File

@@ -2314,28 +2314,23 @@ func RewriteLibs(c LinkableInterface, snapshotInfo **SnapshotInfo, actx android.
return nonvariantLibs, variantLibs
}
func updateDepsWithApiImports(deps Deps, apiImports multitree.ApiImportInfo) Deps {
for idx, lib := range deps.SharedLibs {
deps.SharedLibs[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
func rewriteLibsForApiImports(c LinkableInterface, libs []string, replaceList map[string]string, config android.Config) ([]string, []string) {
nonVariantLibs := []string{}
variantLibs := []string{}
for _, lib := range libs {
replaceLibName := GetReplaceModuleName(lib, replaceList)
if replaceLibName == lib {
// Do not handle any libs which are not in API imports
nonVariantLibs = append(nonVariantLibs, replaceLibName)
} else if c.UseSdk() && inList(replaceLibName, *getNDKKnownLibs(config)) {
variantLibs = append(variantLibs, replaceLibName)
} else {
nonVariantLibs = append(nonVariantLibs, replaceLibName)
}
}
for idx, lib := range deps.LateSharedLibs {
deps.LateSharedLibs[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
}
for idx, lib := range deps.RuntimeLibs {
deps.RuntimeLibs[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
}
for idx, lib := range deps.SystemSharedLibs {
deps.SystemSharedLibs[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
}
for idx, lib := range deps.ReexportSharedLibHeaders {
deps.ReexportSharedLibHeaders[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
}
return deps
return nonVariantLibs, variantLibs
}
func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
@@ -2354,8 +2349,15 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
deps := c.deps(ctx)
apiImportInfo := GetApiImports(c, actx)
apiNdkLibs := []string{}
apiLateNdkLibs := []string{}
if ctx.Os() == android.Android && c.Target().NativeBridge != android.NativeBridgeEnabled {
deps = updateDepsWithApiImports(deps, apiImportInfo)
deps.SharedLibs, apiNdkLibs = rewriteLibsForApiImports(c, deps.SharedLibs, apiImportInfo.SharedLibs, ctx.Config())
deps.LateSharedLibs, apiLateNdkLibs = rewriteLibsForApiImports(c, deps.LateSharedLibs, apiImportInfo.SharedLibs, ctx.Config())
deps.SystemSharedLibs, _ = rewriteLibsForApiImports(c, deps.SystemSharedLibs, apiImportInfo.SharedLibs, ctx.Config())
deps.ReexportHeaderLibHeaders, _ = rewriteLibsForApiImports(c, deps.ReexportHeaderLibHeaders, apiImportInfo.SharedLibs, ctx.Config())
deps.ReexportSharedLibHeaders, _ = rewriteLibsForApiImports(c, deps.ReexportSharedLibHeaders, apiImportInfo.SharedLibs, ctx.Config())
}
c.Properties.AndroidMkSystemSharedLibs = deps.SystemSharedLibs
@@ -2542,12 +2544,20 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
{Mutator: "version", Variation: version},
{Mutator: "link", Variation: "shared"},
}, ndkStubDepTag, variantNdkLibs...)
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "version", Variation: version},
{Mutator: "link", Variation: "shared"},
}, ndkStubDepTag, apiNdkLibs...)
ndkLateStubDepTag := libraryDependencyTag{Kind: sharedLibraryDependency, Order: lateLibraryDependency, ndk: true, makeSuffix: "." + version}
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "version", Variation: version},
{Mutator: "link", Variation: "shared"},
}, ndkLateStubDepTag, variantLateNdkLibs...)
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "version", Variation: version},
{Mutator: "link", Variation: "shared"},
}, ndkLateStubDepTag, apiLateNdkLibs...)
if vndkdep := c.vndkdep; vndkdep != nil {
if vndkdep.isVndkExt() {
@@ -2601,6 +2611,10 @@ func checkLinkType(ctx android.BaseModuleContext, from LinkableInterface, to Lin
}
return
}
// TODO(b/244244438) : Remove this once all variants are implemented
if ccFrom, ok := from.(*Module); ok && ccFrom.isImportedApiLibrary() {
return
}
if from.SdkVersion() == "" {
// Platform code can link to anything
return
@@ -2627,6 +2641,10 @@ func checkLinkType(ctx android.BaseModuleContext, from LinkableInterface, to Lin
// the NDK.
return
}
if c.isImportedApiLibrary() {
// Imported library from the API surface is a stub library built against interface definition.
return
}
}
if strings.HasPrefix(ctx.ModuleName(), "libclang_rt.") && to.Module().Name() == "libc++" {

View File

@@ -15,14 +15,17 @@
package cc
import (
"regexp"
"strings"
"github.com/google/blueprint/proptools"
"android/soong/android"
"android/soong/multitree"
)
var (
ndkVariantRegex = regexp.MustCompile("ndk\\.([a-zA-Z0-9]+)")
)
func init() {
RegisterLibraryStubBuildComponents(android.InitRegistrationContext)
}
@@ -45,13 +48,17 @@ func updateImportedLibraryDependency(ctx android.BottomUpMutatorContext) {
}
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
}
// Add LLNDK variant dependency
if inList("llndk", apiLibrary.properties.Variants) {
variantName := BuildApiVariantName(m.BaseModuleName(), "llndk", "")
ctx.AddDependency(m, nil, variantName)
}
} else if m.IsSdkVariant() {
// Add NDK variant dependencies
targetVariant := "ndk." + m.StubsVersion()
if inList(targetVariant, apiLibrary.properties.Variants) {
variantName := BuildApiVariantName(m.BaseModuleName(), targetVariant, "")
ctx.AddDependency(m, nil, variantName)
}
}
}
@@ -117,12 +124,31 @@ func (d *apiLibraryDecorator) exportIncludes(ctx ModuleContext) {
}
}
func (d *apiLibraryDecorator) linkerInit(ctx BaseModuleContext) {
d.baseLinker.linkerInit(ctx)
if d.hasNDKStubs() {
// Set SDK version of module as current
ctx.Module().(*Module).Properties.Sdk_version = StringPtr("current")
// Add NDK stub as NDK known libs
name := ctx.ModuleName()
ndkKnownLibsLock.Lock()
ndkKnownLibs := getNDKKnownLibs(ctx.Config())
if !inList(name, *ndkKnownLibs) {
*ndkKnownLibs = append(*ndkKnownLibs, name)
}
ndkKnownLibsLock.Unlock()
}
}
func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objects Objects) android.Path {
m, _ := ctx.Module().(*Module)
var in android.Path
if src := proptools.String(d.properties.Src); src != "" {
if src := String(d.properties.Src); src != "" {
in = android.PathForModuleSrc(ctx, src)
}
@@ -149,7 +175,7 @@ func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps
variantMod.exportProperties.Export_headers...)
// Export headers as system include dirs if specified. Mostly for libc
if proptools.Bool(variantMod.exportProperties.Export_headers_as_system) {
if 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...)
@@ -157,6 +183,29 @@ func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps
}
}
}
} else if m.IsSdkVariant() {
// NDK Variant
apiVariantModule := BuildApiVariantName(m.BaseModuleName(), "ndk", m.StubsVersion())
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 NDK 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...)
}
}
}
// Flags reexported from dependencies. (e.g. vndk_prebuilt_shared)
@@ -214,6 +263,14 @@ func (d *apiLibraryDecorator) stubsVersions(ctx android.BaseMutatorContext) []st
// TODO(b/244244438) Create more version information for NDK and APEX variations
// NDK variants
if m.IsSdkVariant() {
// TODO(b/249193999) Do not check if module has NDK stubs once all NDK cc_api_library contains ndk variant of cc_api_variant.
if d.hasNDKStubs() {
return d.getNdkVersions()
}
}
if m.MinSdkVersion() == "" {
return nil
}
@@ -229,14 +286,30 @@ func (d *apiLibraryDecorator) stubsVersions(ctx android.BaseMutatorContext) []st
}
func (d *apiLibraryDecorator) hasLLNDKStubs() bool {
return inList("llndk", d.properties.Variants)
}
func (d *apiLibraryDecorator) hasNDKStubs() bool {
for _, variant := range d.properties.Variants {
if strings.Contains(variant, "llndk") {
if ndkVariantRegex.MatchString(variant) {
return true
}
}
return false
}
func (d *apiLibraryDecorator) getNdkVersions() []string {
ndkVersions := []string{}
for _, variant := range d.properties.Variants {
if match := ndkVariantRegex.FindStringSubmatch(variant); len(match) == 2 {
ndkVersions = append(ndkVersions, match[1])
}
}
return ndkVersions
}
// '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.
@@ -320,18 +393,18 @@ func CcApiVariantFactory() android.Module {
func (v *CcApiVariant) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// No need to build
if proptools.String(v.properties.Src) == "" {
if 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))
v.src = android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), String(v.properties.Src))
}
func (v *CcApiVariant) Name() string {
version := proptools.String(v.properties.Version)
version := String(v.properties.Version)
return BuildApiVariantName(v.BaseModuleName(), *v.properties.Variant, version)
}
@@ -349,8 +422,10 @@ func BuildApiVariantName(baseName string, variant string, version string) string
}
// 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) ImageMutatorBegin(ctx android.BaseModuleContext) {}
func (v *CcApiVariant) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
return String(v.properties.Variant) == "ndk"
}
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 }
@@ -359,7 +434,7 @@ func (v *CcApiVariant) ExtraImageVariations(ctx android.BaseModuleContext) []str
var variations []string
platformVndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
if proptools.String(v.properties.Variant) == "llndk" {
if String(v.properties.Variant) == "llndk" {
variations = append(variations, VendorVariationPrefix+platformVndkVersion)
variations = append(variations, ProductVariationPrefix+platformVndkVersion)
}

View File

@@ -322,16 +322,188 @@ func TestApiLibraryWithLlndkVariant(t *testing.T) {
ctx := prepareForCcTest.RunTestWithBp(t, bp)
libfoo := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Module()
binfoo := 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 from API surface should be linked", true, hasDirectDependency(t, ctx, binfoo, 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")
binFooLibFlags := 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", binFooLibFlags, "libbar_llndk.so")
binFooCFlags := 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", binFooCFlags, "-Ilibbar_llndk_include")
}
func TestApiLibraryWithNdkVariant(t *testing.T) {
bp := `
cc_binary {
name: "binfoo",
sdk_version: "29",
srcs: ["binfoo.cc"],
shared_libs: ["libbar"],
stl: "c++_shared",
}
cc_binary {
name: "binbaz",
sdk_version: "30",
srcs: ["binbaz.cc"],
shared_libs: ["libbar"],
stl: "c++_shared",
}
cc_api_library {
name: "libbar",
// TODO(b/244244438) Remove src property once all variants are implemented.
src: "libbar.so",
variants: [
"ndk.29",
"ndk.30",
"ndk.current",
],
}
cc_api_variant {
name: "libbar",
variant: "ndk",
version: "29",
src: "libbar_ndk_29.so",
export_headers: ["libbar_ndk_29_include"]
}
cc_api_variant {
name: "libbar",
variant: "ndk",
version: "30",
src: "libbar_ndk_30.so",
export_headers: ["libbar_ndk_30_include"]
}
cc_api_variant {
name: "libbar",
variant: "ndk",
version: "current",
src: "libbar_ndk_current.so",
export_headers: ["libbar_ndk_current_include"]
}
api_imports {
name: "api_imports",
shared_libs: [
"libbar",
],
header_libs: [],
}
`
ctx := prepareForCcTest.RunTestWithBp(t, bp)
binfoo := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Module()
libbarApiImportv29 := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_sdk_shared_29").Module()
libbarApiVariantv29 := ctx.ModuleForTests("libbar.ndk.29.apiimport", "android_arm64_armv8-a_sdk").Module()
libbarApiImportv30 := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_sdk_shared_30").Module()
libbarApiVariantv30 := ctx.ModuleForTests("libbar.ndk.30.apiimport", "android_arm64_armv8-a_sdk").Module()
android.AssertBoolEquals(t, "Stub library from API surface should be linked with target version", true, hasDirectDependency(t, ctx, binfoo, libbarApiImportv29))
android.AssertBoolEquals(t, "Stub library variant from API surface should be linked with target version", true, hasDirectDependency(t, ctx, libbarApiImportv29, libbarApiVariantv29))
android.AssertBoolEquals(t, "Stub library from API surface should not be linked with different version", false, hasDirectDependency(t, ctx, binfoo, libbarApiImportv30))
android.AssertBoolEquals(t, "Stub library variant from API surface should not be linked with different version", false, hasDirectDependency(t, ctx, libbarApiImportv29, libbarApiVariantv30))
binbaz := ctx.ModuleForTests("binbaz", "android_arm64_armv8-a_sdk").Module()
android.AssertBoolEquals(t, "Stub library from API surface should be linked with target version", true, hasDirectDependency(t, ctx, binbaz, libbarApiImportv30))
android.AssertBoolEquals(t, "Stub library from API surface should not be linked with different version", false, hasDirectDependency(t, ctx, binbaz, libbarApiImportv29))
binFooLibFlags := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Rule("ld").Args["libFlags"]
android.AssertStringDoesContain(t, "Binary using sdk should be linked with NDK variant source", binFooLibFlags, "libbar_ndk_29.so")
binFooCFlags := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Rule("cc").Args["cFlags"]
android.AssertStringDoesContain(t, "Binary using sdk should include headers from the NDK variant source", binFooCFlags, "-Ilibbar_ndk_29_include")
}
func TestApiLibraryWithMultipleVariants(t *testing.T) {
bp := `
cc_binary {
name: "binfoo",
sdk_version: "29",
srcs: ["binfoo.cc"],
shared_libs: ["libbar"],
stl: "c++_shared",
}
cc_binary {
name: "binbaz",
vendor: true,
srcs: ["binbaz.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",
"ndk.29",
"ndk.30",
"ndk.current",
],
}
cc_api_variant {
name: "libbar",
variant: "ndk",
version: "29",
src: "libbar_ndk_29.so",
export_headers: ["libbar_ndk_29_include"]
}
cc_api_variant {
name: "libbar",
variant: "ndk",
version: "30",
src: "libbar_ndk_30.so",
export_headers: ["libbar_ndk_30_include"]
}
cc_api_variant {
name: "libbar",
variant: "ndk",
version: "current",
src: "libbar_ndk_current.so",
export_headers: ["libbar_ndk_current_include"]
}
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)
binfoo := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Module()
libbarApiImportv29 := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_sdk_shared_29").Module()
libbarApiImportLlndk := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module()
android.AssertBoolEquals(t, "Binary using SDK should be linked with API library from NDK variant", true, hasDirectDependency(t, ctx, binfoo, libbarApiImportv29))
android.AssertBoolEquals(t, "Binary using SDK should not be linked with API library from LLNDK variant", false, hasDirectDependency(t, ctx, binfoo, libbarApiImportLlndk))
binbaz := ctx.ModuleForTests("binbaz", "android_vendor.29_arm64_armv8-a").Module()
android.AssertBoolEquals(t, "Vendor binary should be linked with API library from LLNDK variant", true, hasDirectDependency(t, ctx, binbaz, libbarApiImportLlndk))
android.AssertBoolEquals(t, "Vendor binary should not be linked with API library from NDK variant", false, hasDirectDependency(t, ctx, binbaz, libbarApiImportv29))
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")
}

View File

@@ -31,6 +31,7 @@ func sdkMutator(ctx android.BottomUpMutatorContext) {
switch m := ctx.Module().(type) {
case LinkableInterface:
ccModule, isCcModule := ctx.Module().(*Module)
if m.AlwaysSdk() {
if !m.UseSdk() && !m.SplitPerApiLevel() {
ctx.ModuleErrorf("UseSdk() must return true when AlwaysSdk is set, did the factory forget to set Sdk_version?")
@@ -58,11 +59,32 @@ func sdkMutator(ctx android.BottomUpMutatorContext) {
modules[1].(*Module).Properties.PreventInstall = true
}
ctx.AliasVariation("")
} else if isCcModule && ccModule.isImportedApiLibrary() {
apiLibrary, _ := ccModule.linker.(*apiLibraryDecorator)
if apiLibrary.hasNDKStubs() && ccModule.canUseSdk() {
// Handle cc_api_library module with NDK stubs and variants only which can use SDK
modules := ctx.CreateVariations("", "sdk")
modules[1].(*Module).Properties.IsSdkVariant = true
if ctx.Config().UnbundledBuildApps() {
// For an unbundled apps build, hide the platform variant from Make.
modules[0].(*Module).Properties.HideFromMake = true
modules[0].(*Module).Properties.PreventInstall = true
} else {
// For a platform build, mark the SDK variant so that it gets a ".sdk" suffix when
// exposed to Make.
modules[1].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true
modules[1].(*Module).Properties.PreventInstall = true
}
} else {
ccModule.Properties.Sdk_version = nil
ctx.CreateVariations("")
ctx.AliasVariation("")
}
} else {
if m, ok := ctx.Module().(*Module); ok {
if isCcModule {
// Clear the sdk_version property for modules that don't have an SDK variant so
// later code doesn't get confused by it.
m.Properties.Sdk_version = nil
ccModule.Properties.Sdk_version = nil
}
ctx.CreateVariations("")
ctx.AliasVariation("")
@@ -79,6 +101,11 @@ func sdkMutator(ctx android.BottomUpMutatorContext) {
case *snapshotModule:
ctx.CreateVariations("")
case *CcApiVariant:
ctx.CreateVariations("")
ccApiVariant, _ := ctx.Module().(*CcApiVariant)
if String(ccApiVariant.properties.Variant) == "ndk" {
ctx.CreateVariations("sdk")
} else {
ctx.CreateVariations("")
}
}
}