From ee58c93075ac83fbcea082b1fab0c764bbde3348 Mon Sep 17 00:00:00 2001 From: Kiyoung Kim Date: Tue, 25 Oct 2022 22:59:41 +0900 Subject: [PATCH] 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 --- cc/cc.go | 2 + cc/library.go | 3 +- cc/library_stub.go | 217 ++++++++++++++++++++++++++++++++++++---- cc/library_stub_test.go | 51 ++++++++++ cc/sdk.go | 2 + 5 files changed, 255 insertions(+), 20 deletions(-) diff --git a/cc/cc.go b/cc/cc.go index a8011b842..8840631ea 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -2540,6 +2540,8 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { }, 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 41a68e3cb..aefb80458 100644 --- a/cc/library.go +++ b/cc/library.go @@ -2597,11 +2597,12 @@ func createVersionVariations(mctx android.BottomUpMutatorContext, versions []str 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 760d36ae9..2fb21a31f 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 init() { 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 @@ func RegisterLibraryStubBuildComponents(ctx android.RegistrationContext) { // 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 @@ func CcApiLibraryFactory() android.Module { 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) exportIncludes(ctx ModuleContext) { } 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 @@ func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps 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 @@ func (d *apiLibraryDecorator) availableFor(what string) bool { 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 @@ func CcApiHeadersFactory() android.Module { 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 @@ func (d *apiHeadersDecorator) availableFor(what string) bool { // 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 54b0ba6f0..8ce74c472 100644 --- a/cc/library_stub_test.go +++ b/cc/library_stub_test.go @@ -284,3 +284,54 @@ func TestExportDirFromStubLibrary(t *testing.T) { // 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 a83e5ad2a..a0d196b68 100644 --- a/cc/sdk.go +++ b/cc/sdk.go @@ -78,5 +78,7 @@ func sdkMutator(ctx android.BottomUpMutatorContext) { } case *snapshotModule: ctx.CreateVariations("") + case *CcApiVariant: + ctx.CreateVariations("") } }