Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3a4088df authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Introduce cc_api_library"

parents 258d2966 487689ea
Loading
Loading
Loading
Loading
+58 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import (
	"strings"
	"testing"

	"github.com/google/blueprint"
	"github.com/google/blueprint/proptools"

	"android/soong/android"
@@ -9544,6 +9545,63 @@ func TestUpdatableApexEnforcesAppUpdatability(t *testing.T) {
	}
}

func TestApexBuildsAgainstApiSurfaceStubLibraries(t *testing.T) {
	bp := `
		apex {
			name: "myapex",
			key: "myapex.key",
			native_shared_libs: ["libfoo"],
			min_sdk_version: "29",
		}
		apex_key {
			name: "myapex.key",
		}
		cc_library {
			name: "libfoo",
			shared_libs: ["libc"],
			apex_available: ["myapex"],
			min_sdk_version: "29",
		}
		cc_api_library {
			name: "libc",
			src: "libc.so",
			min_sdk_version: "29",
			recovery_available: true,
		}
		api_imports {
			name: "api_imports",
			shared_libs: [
				"libc",
			],
			header_libs: [],
		}
		`
	result := testApex(t, bp)

	hasDep := func(m android.Module, wantDep android.Module) bool {
		t.Helper()
		var found bool
		result.VisitDirectDeps(m, func(dep blueprint.Module) {
			if dep == wantDep {
				found = true
			}
		})
		return found
	}

	libfooApexVariant := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared_apex29").Module()
	libcApexVariant := result.ModuleForTests("libc.apiimport", "android_arm64_armv8-a_shared_apex29").Module()

	android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries", true, hasDep(libfooApexVariant, libcApexVariant))

	// libfoo core variant should be buildable in the same inner tree since
	// certain mcombo files might build system and apexes in the same inner tree
	// libfoo core variant should link against source libc
	libfooCoreVariant := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
	libcCoreVariant := result.ModuleForTests("libc.apiimport", "android_arm64_armv8-a_shared").Module()
	android.AssertBoolEquals(t, "core variant should link against source libc", true, hasDep(libfooCoreVariant, libcCoreVariant))
}

func TestMain(m *testing.M) {
	os.Exit(m.Run())
}
+88 −25
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import (
	"android/soong/cc/config"
	"android/soong/fuzz"
	"android/soong/genrule"
	"android/soong/multitree"
	"android/soong/snapshot"
)

@@ -2183,6 +2184,24 @@ func AddSharedLibDependenciesWithVersions(ctx android.BottomUpMutatorContext, mo
	}
}

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.
@@ -2208,8 +2227,8 @@ func GetSnapshot(c LinkableInterface, snapshotInfo **SnapshotInfo, actx android.
	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
	}

@@ -2220,12 +2239,17 @@ func RewriteSnapshotLib(lib string, snapshotMap map[string]string) string {
// 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.
//
// 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.
//
// 3. Anything else (so anything that isn't an NDK library).
//
//	It adds these to the nonvariantLibs list.
//
// The caller can then know to add the variantLibs dependencies differently from the
@@ -2238,11 +2262,11 @@ func RewriteLibs(c LinkableInterface, snapshotInfo **SnapshotInfo, actx android.
		// 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)
@@ -2251,6 +2275,25 @@ 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)
	}

	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
@@ -2266,6 +2309,9 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {

	deps := c.deps(ctx)

	apiImportInfo := GetApiImports(c, actx)
	deps = updateDepsWithApiImports(deps, apiImportInfo)

	c.Properties.AndroidMkSystemSharedLibs = deps.SystemSharedLibs

	var snapshotInfo *SnapshotInfo
@@ -2278,7 +2324,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
		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)
		}
	}

@@ -2288,7 +2334,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
			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()),
@@ -2301,11 +2347,21 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
	if c.isNDKStubLibrary() {
		// NDK stubs depend on their implementation because the ABI dumps are
		// generated from the implementation library.
		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
	// C++ implementation library and one Java implementation library. When a module links against
@@ -2320,7 +2376,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
			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"},
@@ -2340,7 +2396,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
			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"},
@@ -2354,7 +2410,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
		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
@@ -2386,14 +2442,14 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
		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 {
@@ -2434,11 +2490,11 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
	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)
@@ -2463,7 +2519,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
			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))
		}
	}
}
@@ -3185,6 +3241,11 @@ func MakeLibName(ctx android.ModuleContext, c LinkableInterface, ccDep LinkableI

			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() &&
@@ -3520,6 +3581,10 @@ func (c *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
	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
@@ -3637,9 +3702,7 @@ func (c *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
	}
}

//
// Defaults
//
type Defaults struct {
	android.ModuleBase
	android.DefaultsModuleBase
+87 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ package cc
import (
	"android/soong/android"
	"android/soong/multitree"
	"strings"
)

func init() {
@@ -25,10 +26,96 @@ func init() {

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{
+110 −0
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import (

	"android/soong/android"
	"android/soong/multitree"

	"github.com/google/blueprint"
)

func TestCcApiStubLibraryOutputFiles(t *testing.T) {
@@ -106,3 +108,111 @@ func TestApiSurfaceOutputs(t *testing.T) {
	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))
}
+3 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import (

	"android/soong/android"
	"android/soong/genrule"
	"android/soong/multitree"
	"android/soong/snapshot"
)

@@ -31,6 +32,8 @@ func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) {
	RegisterLibraryHeadersBuildComponents(ctx)
	RegisterLibraryStubBuildComponents(ctx)

	multitree.RegisterApiImportsModule(ctx)

	ctx.RegisterModuleType("cc_benchmark", BenchmarkFactory)
	ctx.RegisterModuleType("cc_object", ObjectFactory)
	ctx.RegisterModuleType("cc_genrule", GenRuleFactory)
Loading