diff --git a/cc/cc.go b/cc/cc.go index 8b3f4562e..2ff5bbacc 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -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++" { diff --git a/cc/library_stub.go b/cc/library_stub.go index 043c03c30..22e61a768 100644 --- a/cc/library_stub.go +++ b/cc/library_stub.go @@ -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) } diff --git a/cc/library_stub_test.go b/cc/library_stub_test.go index 8ce74c472..e3728606a 100644 --- a/cc/library_stub_test.go +++ b/cc/library_stub_test.go @@ -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") } diff --git a/cc/sdk.go b/cc/sdk.go index a0d196b68..3e50c9f4b 100644 --- a/cc/sdk.go +++ b/cc/sdk.go @@ -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("") + } } }