Introduce cc_api_library
Introduce cc_api_library, which reflects imported API from other
inner-tree. This cc_api_library module type will later refer from
the other ninja module which generates stub library from the interface
description.
Tested environment :
* original libc definition has been removed temporarily, to ensure that
imported api stub library is being used from build
* Added new definition of libc as below
cc_api_library {
name: "libc",
arch: {
x86: {
src: "libs/x86/libc.so",
},
x86_64: {
src: "libs/x86_64/libc.so",
},
},
header_libs: [
"libc_headers",
],
export_header_lib_headers: ["libc_headers"],
min_sdk_version: "9",
vendor_available: true,
}
Bug: 236087698
Test: `ALLOW_MISSING_DEPENDENCIES=true m vendorimage` succeeded
Change-Id: I67070b0f3561aa2afd73b6c1c0fdf4255218baac
diff --git a/cc/cc.go b/cc/cc.go
index bc95813..471267a 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -31,6 +31,7 @@
"android/soong/cc/config"
"android/soong/fuzz"
"android/soong/genrule"
+ "android/soong/multitree"
"android/soong/snapshot"
)
@@ -2184,6 +2185,24 @@
}
}
+func GetApiImports(c LinkableInterface, actx android.BottomUpMutatorContext) multitree.ApiImportInfo {
+ apiImportInfo := multitree.ApiImportInfo{}
+
+ if c.Device() {
+ var apiImportModule []blueprint.Module
+ if actx.OtherModuleExists("api_imports") {
+ apiImportModule = actx.AddDependency(c, nil, "api_imports")
+ if len(apiImportModule) > 0 && apiImportModule[0] != nil {
+ apiInfo := actx.OtherModuleProvider(apiImportModule[0], multitree.ApiImportsProvider).(multitree.ApiImportInfo)
+ apiImportInfo = apiInfo
+ actx.SetProvider(multitree.ApiImportsProvider, apiInfo)
+ }
+ }
+ }
+
+ return apiImportInfo
+}
+
func GetSnapshot(c LinkableInterface, snapshotInfo **SnapshotInfo, actx android.BottomUpMutatorContext) SnapshotInfo {
// Only device modules with BOARD_VNDK_VERSION uses snapshot. Others use the zero value of
// SnapshotInfo, which provides no mappings.
@@ -2209,8 +2228,8 @@
return **snapshotInfo
}
-func RewriteSnapshotLib(lib string, snapshotMap map[string]string) string {
- if snapshot, ok := snapshotMap[lib]; ok {
+func GetReplaceModuleName(lib string, replaceMap map[string]string) string {
+ if snapshot, ok := replaceMap[lib]; ok {
return snapshot
}
@@ -2221,13 +2240,18 @@
// of names:
//
// 1. Name of an NDK library that refers to a prebuilt module.
-// For each of these, it adds the name of the prebuilt module (which will be in
-// prebuilts/ndk) to the list of nonvariant libs.
+//
+// For each of these, it adds the name of the prebuilt module (which will be in
+// prebuilts/ndk) to the list of nonvariant libs.
+//
// 2. Name of an NDK library that refers to an ndk_library module.
-// For each of these, it adds the name of the ndk_library module to the list of
-// variant libs.
+//
+// For each of these, it adds the name of the ndk_library module to the list of
+// variant libs.
+//
// 3. Anything else (so anything that isn't an NDK library).
-// It adds these to the nonvariantLibs list.
+//
+// It adds these to the nonvariantLibs list.
//
// The caller can then know to add the variantLibs dependencies differently from the
// nonvariantLibs
@@ -2239,11 +2263,11 @@
// strip #version suffix out
name, _ := StubsLibNameAndVersion(entry)
if c.InRecovery() {
- nonvariantLibs = append(nonvariantLibs, RewriteSnapshotLib(entry, GetSnapshot(c, snapshotInfo, actx).SharedLibs))
+ nonvariantLibs = append(nonvariantLibs, GetReplaceModuleName(entry, GetSnapshot(c, snapshotInfo, actx).SharedLibs))
} else if c.UseSdk() && inList(name, *getNDKKnownLibs(config)) {
variantLibs = append(variantLibs, name+ndkLibrarySuffix)
} else if c.UseVndk() {
- nonvariantLibs = append(nonvariantLibs, RewriteSnapshotLib(entry, GetSnapshot(c, snapshotInfo, actx).SharedLibs))
+ nonvariantLibs = append(nonvariantLibs, GetReplaceModuleName(entry, GetSnapshot(c, snapshotInfo, actx).SharedLibs))
} else {
// put name#version back
nonvariantLibs = append(nonvariantLibs, entry)
@@ -2252,6 +2276,25 @@
return nonvariantLibs, variantLibs
}
+func updateDepsWithApiImports(deps Deps, apiImports multitree.ApiImportInfo) Deps {
+ for idx, lib := range deps.SharedLibs {
+ deps.SharedLibs[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
+ }
+
+ 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.HeaderLibs {
+ deps.HeaderLibs[idx] = GetReplaceModuleName(lib, apiImports.HeaderLibs)
+ }
+ return deps
+}
+
func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
if !c.Enabled() {
return
@@ -2267,6 +2310,9 @@
deps := c.deps(ctx)
+ apiImportInfo := GetApiImports(c, actx)
+ deps = updateDepsWithApiImports(deps, apiImportInfo)
+
c.Properties.AndroidMkSystemSharedLibs = deps.SystemSharedLibs
var snapshotInfo *SnapshotInfo
@@ -2279,7 +2325,7 @@
deps.ReexportSharedLibHeaders, _ = RewriteLibs(c, &snapshotInfo, actx, ctx.Config(), deps.ReexportSharedLibHeaders)
for idx, lib := range deps.RuntimeLibs {
- deps.RuntimeLibs[idx] = RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).SharedLibs)
+ deps.RuntimeLibs[idx] = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).SharedLibs)
}
}
@@ -2289,7 +2335,7 @@
depTag.reexportFlags = true
}
- lib = RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).HeaderLibs)
+ lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).HeaderLibs)
if c.IsStubs() {
actx.AddFarVariationDependencies(append(ctx.Target().Variations(), c.ImageVariation()),
@@ -2302,10 +2348,20 @@
if c.isNDKStubLibrary() {
// NDK stubs depend on their implementation because the ABI dumps are
// generated from the implementation library.
- actx.AddFarVariationDependencies(append(ctx.Target().Variations(),
- c.ImageVariation(),
- blueprint.Variation{Mutator: "link", Variation: "shared"},
- ), stubImplementation, c.BaseModuleName())
+ apiImportName := c.BaseModuleName() + multitree.GetApiImportSuffix()
+
+ // If original library exists as imported API, set dependency on the imported library
+ if actx.OtherModuleExists(apiImportName) {
+ actx.AddFarVariationDependencies(append(ctx.Target().Variations(),
+ c.ImageVariation(),
+ blueprint.Variation{Mutator: "link", Variation: "shared"},
+ ), stubImplementation, apiImportName)
+ } else {
+ actx.AddFarVariationDependencies(append(ctx.Target().Variations(),
+ c.ImageVariation(),
+ blueprint.Variation{Mutator: "link", Variation: "shared"},
+ ), stubImplementation, c.BaseModuleName())
+ }
}
// sysprop_library has to support both C++ and Java. So sysprop_library internally creates one
@@ -2321,7 +2377,7 @@
lib = impl
}
- lib = RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs)
+ lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs)
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
@@ -2341,7 +2397,7 @@
lib = impl
}
- lib = RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs)
+ lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs)
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
@@ -2355,7 +2411,7 @@
depTag := libraryDependencyTag{Kind: staticLibraryDependency, staticUnwinder: true}
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
- }, depTag, RewriteSnapshotLib(staticUnwinder(actx), GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
+ }, depTag, GetReplaceModuleName(staticUnwinder(actx), GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
}
// shared lib names without the #version suffix
@@ -2387,14 +2443,14 @@
depTag := libraryDependencyTag{Kind: staticLibraryDependency, Order: lateLibraryDependency}
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
- }, depTag, RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
+ }, depTag, GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
}
for _, lib := range deps.UnexportedStaticLibs {
depTag := libraryDependencyTag{Kind: staticLibraryDependency, Order: lateLibraryDependency, unexportedSymbols: true}
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
- }, depTag, RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
+ }, depTag, GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
}
for _, lib := range deps.LateSharedLibs {
@@ -2435,11 +2491,11 @@
actx.AddVariationDependencies(crtVariations, objDepTag, deps.ObjFiles...)
for _, crt := range deps.CrtBegin {
actx.AddVariationDependencies(crtVariations, CrtBeginDepTag,
- RewriteSnapshotLib(crt, GetSnapshot(c, &snapshotInfo, actx).Objects))
+ GetReplaceModuleName(crt, GetSnapshot(c, &snapshotInfo, actx).Objects))
}
for _, crt := range deps.CrtEnd {
actx.AddVariationDependencies(crtVariations, CrtEndDepTag,
- RewriteSnapshotLib(crt, GetSnapshot(c, &snapshotInfo, actx).Objects))
+ GetReplaceModuleName(crt, GetSnapshot(c, &snapshotInfo, actx).Objects))
}
if deps.DynamicLinker != "" {
actx.AddDependency(c, dynamicLinkerDepTag, deps.DynamicLinker)
@@ -2464,7 +2520,7 @@
actx.AddVariationDependencies([]blueprint.Variation{
c.ImageVariation(),
{Mutator: "link", Variation: "shared"},
- }, vndkExtDepTag, RewriteSnapshotLib(vndkdep.getVndkExtendsModuleName(), GetSnapshot(c, &snapshotInfo, actx).SharedLibs))
+ }, vndkExtDepTag, GetReplaceModuleName(vndkdep.getVndkExtendsModuleName(), GetSnapshot(c, &snapshotInfo, actx).SharedLibs))
}
}
}
@@ -3186,6 +3242,11 @@
return baseName + snapshotPrebuilt.SnapshotAndroidMkSuffix()
}
+
+ // Remove API import suffix if exists
+ if _, ok := ccDepModule.linker.(*apiLibraryDecorator); ok {
+ libName = strings.TrimSuffix(libName, multitree.GetApiImportSuffix())
+ }
}
if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() &&
@@ -3521,6 +3582,10 @@
if _, ok := c.linker.(prebuiltLinkerInterface); ok {
return nil
}
+ if _, ok := c.linker.(*apiLibraryDecorator); ok {
+ return nil
+ }
+
minSdkVersion := c.MinSdkVersion()
if minSdkVersion == "apex_inherit" {
return nil
@@ -3638,9 +3703,7 @@
}
}
-//
// Defaults
-//
type Defaults struct {
android.ModuleBase
android.DefaultsModuleBase
diff --git a/cc/library_stub.go b/cc/library_stub.go
index 4d0148d..14d1b96 100644
--- a/cc/library_stub.go
+++ b/cc/library_stub.go
@@ -17,6 +17,7 @@
import (
"android/soong/android"
"android/soong/multitree"
+ "strings"
)
func init() {
@@ -25,10 +26,96 @@
func RegisterLibraryStubBuildComponents(ctx android.RegistrationContext) {
// cc_api_stub_library shares a lot of ndk_library, and this will be refactored later
+ ctx.RegisterModuleType("cc_api_library", CcApiLibraryFactory)
ctx.RegisterModuleType("cc_api_stub_library", CcApiStubLibraryFactory)
ctx.RegisterModuleType("cc_api_contribution", CcApiContributionFactory)
}
+// 'cc_api_library' is a module type which is from the exported API surface
+// with C shared library type. The module will replace original module, and
+// offer a link to the module that generates shared library object from the
+// map file.
+type apiLibraryProperties struct {
+ Src *string `android:"arch_variant"`
+}
+
+type apiLibraryDecorator struct {
+ *libraryDecorator
+ properties apiLibraryProperties
+}
+
+func CcApiLibraryFactory() android.Module {
+ module, decorator := NewLibrary(android.DeviceSupported)
+ apiLibraryDecorator := &apiLibraryDecorator{
+ libraryDecorator: decorator,
+ }
+ apiLibraryDecorator.BuildOnlyShared()
+
+ module.stl = nil
+ module.sanitize = nil
+ decorator.disableStripping()
+
+ module.compiler = nil
+ module.linker = apiLibraryDecorator
+ module.installer = nil
+ 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{}
+ }
+
+ module.Init()
+
+ return module
+}
+
+func (d *apiLibraryDecorator) Name(basename string) string {
+ return basename + multitree.GetApiImportSuffix()
+}
+
+func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objects Objects) android.Path {
+ // Flags reexported from dependencies. (e.g. vndk_prebuilt_shared)
+ d.libraryDecorator.flagExporter.exportIncludes(ctx)
+ d.libraryDecorator.reexportDirs(deps.ReexportedDirs...)
+ d.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...)
+ d.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
+ d.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
+ d.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
+ d.libraryDecorator.flagExporter.setProvider(ctx)
+
+ in := android.PathForModuleSrc(ctx, *d.properties.Src)
+
+ d.unstrippedOutputFile = in
+ libName := d.libraryDecorator.getLibName(ctx) + flags.Toolchain.ShlibSuffix()
+
+ tocFile := android.PathForModuleOut(ctx, libName+".toc")
+ d.tocFile = android.OptionalPathForPath(tocFile)
+ TransformSharedObjectToToc(ctx, in, tocFile)
+
+ ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+ SharedLibrary: in,
+ Target: ctx.Target(),
+
+ TableOfContents: d.tocFile,
+ })
+
+ return in
+}
+
+func (d *apiLibraryDecorator) availableFor(what string) bool {
+ // Stub from API surface should be available for any APEX.
+ return true
+}
+
+func (d *apiLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
+ d.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), multitree.GetApiImportSuffix())
+ return d.libraryDecorator.linkerFlags(ctx, flags)
+}
+
func CcApiStubLibraryFactory() android.Module {
module, decorator := NewLibrary(android.DeviceSupported)
apiStubDecorator := &apiStubDecorator{
diff --git a/cc/library_stub_test.go b/cc/library_stub_test.go
index 15b56d2..c2ac941 100644
--- a/cc/library_stub_test.go
+++ b/cc/library_stub_test.go
@@ -22,6 +22,8 @@
"android/soong/android"
"android/soong/multitree"
+
+ "github.com/google/blueprint"
)
func TestCcApiStubLibraryOutputFiles(t *testing.T) {
@@ -106,3 +108,111 @@
android.AssertStringEquals(t, "name", "foo.mysdk", api_surface_gen_rule_args["name"])
android.AssertStringEquals(t, "symbol_file", "foo.map.txt", api_surface_gen_rule_args["symbol_file"])*/
}
+
+func hasDirectDependency(t *testing.T, ctx *android.TestResult, from android.Module, to android.Module) bool {
+ t.Helper()
+ var found bool
+ ctx.VisitDirectDeps(from, func(dep blueprint.Module) {
+ if dep == to {
+ found = true
+ }
+ })
+ return found
+}
+
+func TestApiLibraryReplacesExistingModule(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "libfoo",
+ shared_libs: ["libbar"],
+ }
+
+ cc_library {
+ name: "libbar",
+ }
+
+ cc_api_library {
+ name: "libbar",
+ src: "libbar.so",
+ }
+
+ api_imports {
+ name: "api_imports",
+ shared_libs: [
+ "libbar",
+ ],
+ header_libs: [],
+ }
+ `
+
+ ctx := prepareForCcTest.RunTestWithBp(t, bp)
+
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
+ libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
+ libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
+
+ android.AssertBoolEquals(t, "original library should not be linked", false, hasDirectDependency(t, ctx, libfoo, libbar))
+ android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
+}
+
+func TestApiLibraryDoNotRequireOriginalModule(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "libfoo",
+ shared_libs: ["libbar"],
+ }
+
+ cc_api_library {
+ name: "libbar",
+ src: "libbar.so",
+ }
+
+ api_imports {
+ name: "api_imports",
+ shared_libs: [
+ "libbar",
+ ],
+ header_libs: [],
+ }
+ `
+
+ ctx := prepareForCcTest.RunTestWithBp(t, bp)
+
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
+ libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
+
+ android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
+}
+
+func TestApiLibraryShouldNotReplaceWithoutApiImport(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "libfoo",
+ shared_libs: ["libbar"],
+ }
+
+ cc_library {
+ name: "libbar",
+ }
+
+ cc_api_library {
+ name: "libbar",
+ src: "libbar.so",
+ }
+
+ api_imports {
+ name: "api_imports",
+ shared_libs: [],
+ header_libs: [],
+ }
+ `
+
+ ctx := prepareForCcTest.RunTestWithBp(t, bp)
+
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
+ libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
+ libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
+
+ android.AssertBoolEquals(t, "original library should be linked", true, hasDirectDependency(t, ctx, libfoo, libbar))
+ android.AssertBoolEquals(t, "Stub library from API surface should not be linked", false, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
+}
diff --git a/cc/testing.go b/cc/testing.go
index 6b858d5..40edd28 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -20,6 +20,7 @@
"android/soong/android"
"android/soong/genrule"
+ "android/soong/multitree"
"android/soong/snapshot"
)
@@ -31,6 +32,8 @@
RegisterLibraryHeadersBuildComponents(ctx)
RegisterLibraryStubBuildComponents(ctx)
+ multitree.RegisterApiImportsModule(ctx)
+
ctx.RegisterModuleType("cc_benchmark", BenchmarkFactory)
ctx.RegisterModuleType("cc_object", ObjectFactory)
ctx.RegisterModuleType("cc_genrule", GenRuleFactory)