Remove global state from version mutator

A per-context variable is used to store the list of modules that
contain stubs and their available versions.  Stores the list of the
stubs versions on the implementation module, and then use the new
return values from AddVariationDependencies to expand dependencies
on implementation libraries to also depend on the stubs libraries.
Adds a new mutator pass to propagate list of stub versions to llndk
libraries.

Also creates an alias version variation called "latest" to allow
depending on the latest version without having to know what it is.

Test: all Soong tests
Test: no change to build.ninja, Android-${TARGET_PRODUCT}.mk, make_vars-${TARGET_PRODUCT}.mk or late-${TARGET_PRODUCT}.mk
Change-Id: If19659e2e5828c860fd4d679ef79a414b7ea2efc
This commit is contained in:
Colin Cross 2020-08-18 18:35:15 -07:00
parent 4f1dcb0e40
commit d1f898e70a
7 changed files with 85 additions and 66 deletions

View file

@ -44,7 +44,7 @@ func (mt *binarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorConte
for _, target := range targets { for _, target := range targets {
name, version := StubsLibNameAndVersion(lib) name, version := StubsLibNameAndVersion(lib)
if version == "" { if version == "" {
version = LatestStubsVersionFor(mctx.Config(), name) version = "latest"
} }
variations := target.Variations() variations := target.Variations()
if mctx.Device() { if mctx.Device() {

View file

@ -47,7 +47,8 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) {
ctx.BottomUp("link", LinkageMutator).Parallel() ctx.BottomUp("link", LinkageMutator).Parallel()
ctx.BottomUp("ndk_api", NdkApiMutator).Parallel() ctx.BottomUp("ndk_api", NdkApiMutator).Parallel()
ctx.BottomUp("test_per_src", TestPerSrcMutator).Parallel() ctx.BottomUp("test_per_src", TestPerSrcMutator).Parallel()
ctx.BottomUp("version", VersionMutator).Parallel() ctx.BottomUp("version_selector", versionSelectorMutator).Parallel()
ctx.BottomUp("version", versionMutator).Parallel()
ctx.BottomUp("begin", BeginMutator).Parallel() ctx.BottomUp("begin", BeginMutator).Parallel()
ctx.BottomUp("sysprop_cc", SyspropMutator).Parallel() ctx.BottomUp("sysprop_cc", SyspropMutator).Parallel()
ctx.BottomUp("vendor_snapshot", VendorSnapshotMutator).Parallel() ctx.BottomUp("vendor_snapshot", VendorSnapshotMutator).Parallel()
@ -784,7 +785,28 @@ func (c *Module) BuildStubs() bool {
panic(fmt.Errorf("BuildStubs called on non-library module: %q", c.BaseModuleName())) panic(fmt.Errorf("BuildStubs called on non-library module: %q", c.BaseModuleName()))
} }
func (c *Module) SetStubsVersions(version string) { func (c *Module) SetAllStubsVersions(versions []string) {
if library, ok := c.linker.(*libraryDecorator); ok {
library.MutatedProperties.AllStubsVersions = versions
return
}
if llndk, ok := c.linker.(*llndkStubDecorator); ok {
llndk.libraryDecorator.MutatedProperties.AllStubsVersions = versions
return
}
}
func (c *Module) AllStubsVersions() []string {
if library, ok := c.linker.(*libraryDecorator); ok {
return library.MutatedProperties.AllStubsVersions
}
if llndk, ok := c.linker.(*llndkStubDecorator); ok {
return llndk.libraryDecorator.MutatedProperties.AllStubsVersions
}
return nil
}
func (c *Module) SetStubsVersion(version string) {
if c.linker != nil { if c.linker != nil {
if library, ok := c.linker.(*libraryDecorator); ok { if library, ok := c.linker.(*libraryDecorator); ok {
library.MutatedProperties.StubsVersion = version library.MutatedProperties.StubsVersion = version
@ -795,7 +817,7 @@ func (c *Module) SetStubsVersions(version string) {
return return
} }
} }
panic(fmt.Errorf("SetStubsVersions called on non-library module: %q", c.BaseModuleName())) panic(fmt.Errorf("SetStubsVersion called on non-library module: %q", c.BaseModuleName()))
} }
func (c *Module) StubsVersion() string { func (c *Module) StubsVersion() string {
@ -1994,18 +2016,20 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version}) variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
depTag.explicitlyVersioned = true depTag.explicitlyVersioned = true
} }
actx.AddVariationDependencies(variations, depTag, name) deps := actx.AddVariationDependencies(variations, depTag, name)
// If the version is not specified, add dependency to all stubs libraries. // If the version is not specified, add dependency to all stubs libraries.
// The stubs library will be used when the depending module is built for APEX and // The stubs library will be used when the depending module is built for APEX and
// the dependent module is not in the same APEX. // the dependent module is not in the same APEX.
if version == "" && VersionVariantAvailable(c) { if version == "" && VersionVariantAvailable(c) {
for _, ver := range stubsVersionsFor(actx.Config())[name] { if dep, ok := deps[0].(*Module); ok {
// Note that depTag.ExplicitlyVersioned is false in this case. for _, ver := range dep.AllStubsVersions() {
actx.AddVariationDependencies([]blueprint.Variation{ // Note that depTag.ExplicitlyVersioned is false in this case.
{Mutator: "link", Variation: "shared"}, ctx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "version", Variation: ver}, {Mutator: "link", Variation: "shared"},
}, depTag, name) {Mutator: "version", Variation: ver},
}, depTag, name)
}
} }
} }
} }
@ -2457,7 +2481,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
if m, ok := ccDep.(*Module); ok && m.IsStubs() { // LLNDK if m, ok := ccDep.(*Module); ok && m.IsStubs() { // LLNDK
// by default, use current version of LLNDK // by default, use current version of LLNDK
versionToUse := "" versionToUse := ""
versions := stubsVersionsFor(ctx.Config())[depName] versions := m.AllStubsVersions()
if c.ApexVariationName() != "" && len(versions) > 0 { if c.ApexVariationName() != "" && len(versions) > 0 {
// if this is for use_vendor apex && dep has stubsVersions // if this is for use_vendor apex && dep has stubsVersions
// apply the same rule of apex sdk enforcement to choose right version // apply the same rule of apex sdk enforcement to choose right version

View file

@ -3025,6 +3025,7 @@ func TestStaticLibDepReorderingWithShared(t *testing.T) {
} }
func checkEquals(t *testing.T, message string, expected, actual interface{}) { func checkEquals(t *testing.T, message string, expected, actual interface{}) {
t.Helper()
if !reflect.DeepEqual(actual, expected) { if !reflect.DeepEqual(actual, expected) {
t.Errorf(message+ t.Errorf(message+
"\nactual: %v"+ "\nactual: %v"+

View file

@ -152,6 +152,8 @@ type LibraryMutatedProperties struct {
BuildStubs bool `blueprint:"mutated"` BuildStubs bool `blueprint:"mutated"`
// Version of the stubs lib // Version of the stubs lib
StubsVersion string `blueprint:"mutated"` StubsVersion string `blueprint:"mutated"`
// List of all stubs versions associated with an implementation lib
AllStubsVersions []string `blueprint:"mutated"`
} }
type FlagExporterProperties struct { type FlagExporterProperties struct {
@ -1517,26 +1519,6 @@ func LinkageMutator(mctx android.BottomUpMutatorContext) {
} }
} }
var stubVersionsKey = android.NewOnceKey("stubVersions")
// maps a module name to the list of stubs versions available for the module
func stubsVersionsFor(config android.Config) map[string][]string {
return config.Once(stubVersionsKey, func() interface{} {
return make(map[string][]string)
}).(map[string][]string)
}
var stubsVersionsLock sync.Mutex
func LatestStubsVersionFor(config android.Config, name string) string {
versions, ok := stubsVersionsFor(config)[name]
if ok && len(versions) > 0 {
// the versions are alreay sorted in ascending order
return versions[len(versions)-1]
}
return ""
}
func normalizeVersions(ctx android.BaseModuleContext, versions []string) { func normalizeVersions(ctx android.BaseModuleContext, versions []string) {
numVersions := make([]int, len(versions)) numVersions := make([]int, len(versions))
for i, v := range versions { for i, v := range versions {
@ -1556,17 +1538,22 @@ func normalizeVersions(ctx android.BaseModuleContext, versions []string) {
} }
func createVersionVariations(mctx android.BottomUpMutatorContext, versions []string) { func createVersionVariations(mctx android.BottomUpMutatorContext, versions []string) {
// "" is for the non-stubs variant // "" is for the non-stubs (implementation) variant.
versions = append([]string{""}, versions...) variants := append([]string{""}, versions...)
modules := mctx.CreateLocalVariations(versions...) modules := mctx.CreateLocalVariations(variants...)
for i, m := range modules { for i, m := range modules {
if versions[i] != "" { if variants[i] != "" {
m.(LinkableInterface).SetBuildStubs() m.(LinkableInterface).SetBuildStubs()
m.(LinkableInterface).SetStubsVersions(versions[i]) m.(LinkableInterface).SetStubsVersion(variants[i])
} }
} }
mctx.AliasVariation("") mctx.AliasVariation("")
latestVersion := ""
if len(versions) > 0 {
latestVersion = versions[len(versions)-1]
}
mctx.CreateAliasVariation("latest", latestVersion)
} }
func VersionVariantAvailable(module interface { func VersionVariantAvailable(module interface {
@ -1577,44 +1564,41 @@ func VersionVariantAvailable(module interface {
return !module.Host() && !module.InRamdisk() && !module.InRecovery() return !module.Host() && !module.InRamdisk() && !module.InRecovery()
} }
// VersionMutator splits a module into the mandatory non-stubs variant // versionSelector normalizes the versions in the Stubs.Versions property into MutatedProperties.AllStubsVersions,
// (which is unnamed) and zero or more stubs variants. // and propagates the value from implementation libraries to llndk libraries with the same name.
func VersionMutator(mctx android.BottomUpMutatorContext) { func versionSelectorMutator(mctx android.BottomUpMutatorContext) {
if library, ok := mctx.Module().(LinkableInterface); ok && VersionVariantAvailable(library) { if library, ok := mctx.Module().(LinkableInterface); ok && VersionVariantAvailable(library) {
if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 && if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 &&
!library.IsSdkVariant() { !library.IsSdkVariant() {
versions := library.StubsVersions() versions := library.StubsVersions()
normalizeVersions(mctx, versions) normalizeVersions(mctx, versions)
if mctx.Failed() { if mctx.Failed() {
return return
} }
// Set the versions on the pre-mutated module so they can be read by any llndk modules that
stubsVersionsLock.Lock() // depend on the implementation library and haven't been mutated yet.
defer stubsVersionsLock.Unlock() library.SetAllStubsVersions(versions)
// save the list of versions for later use
stubsVersionsFor(mctx.Config())[mctx.ModuleName()] = versions
createVersionVariations(mctx, versions)
return return
} }
if c, ok := library.(*Module); ok && c.IsStubs() { if c, ok := library.(*Module); ok && c.IsStubs() {
stubsVersionsLock.Lock() // Get the versions from the implementation module.
defer stubsVersionsLock.Unlock() impls := mctx.GetDirectDepsWithTag(llndkImplDep)
// For LLNDK llndk_library, we borrow stubs.versions from its implementation library. if len(impls) > 1 {
// Since llndk_library has dependency to its implementation library, panic(fmt.Errorf("Expected single implmenetation library, got %d", len(impls)))
// we can safely access stubsVersionsFor() with its baseModuleName. } else if len(impls) == 1 {
versions := stubsVersionsFor(mctx.Config())[c.BaseModuleName()] c.SetAllStubsVersions(impls[0].(*Module).AllStubsVersions())
// save the list of versions for later use }
stubsVersionsFor(mctx.Config())[mctx.ModuleName()] = versions
createVersionVariations(mctx, versions)
return
} }
}
}
mctx.CreateLocalVariations("") // versionMutator splits a module into the mandatory non-stubs variant
mctx.AliasVariation("") // (which is unnamed) and zero or more stubs variants.
return func versionMutator(mctx android.BottomUpMutatorContext) {
if library, ok := mctx.Module().(LinkableInterface); ok && VersionVariantAvailable(library) {
createVersionVariations(mctx, library.AllStubsVersions())
} }
} }

View file

@ -80,7 +80,7 @@ func (mt *librarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorCont
for _, target := range targets { for _, target := range targets {
name, version := StubsLibNameAndVersion(lib) name, version := StubsLibNameAndVersion(lib)
if version == "" { if version == "" {
version = LatestStubsVersionFor(mctx.Config(), name) version = "latest"
} }
variations := target.Variations() variations := target.Variations()
if mctx.Device() { if mctx.Device() {

View file

@ -26,8 +26,10 @@ type LinkableInterface interface {
StubsVersions() []string StubsVersions() []string
BuildStubs() bool BuildStubs() bool
SetBuildStubs() SetBuildStubs()
SetStubsVersions(string) SetStubsVersion(string)
StubsVersion() string StubsVersion() string
SetAllStubsVersions([]string)
AllStubsVersions() []string
HasStubsVariants() bool HasStubsVariants() bool
SelectedStl() string SelectedStl() string
ApiLevel() string ApiLevel() string

View file

@ -458,12 +458,20 @@ func (mod *Module) SetBuildStubs() {
panic("SetBuildStubs not yet implemented for rust modules") panic("SetBuildStubs not yet implemented for rust modules")
} }
func (mod *Module) SetStubsVersions(string) { func (mod *Module) SetStubsVersion(string) {
panic("SetStubsVersions not yet implemented for rust modules") panic("SetStubsVersion not yet implemented for rust modules")
} }
func (mod *Module) StubsVersion() string { func (mod *Module) StubsVersion() string {
panic("SetStubsVersions not yet implemented for rust modules") panic("StubsVersion not yet implemented for rust modules")
}
func (mod *Module) SetAllStubsVersions([]string) {
panic("SetAllStubsVersions not yet implemented for rust modules")
}
func (mod *Module) AllStubsVersions() []string {
return nil
} }
func (mod *Module) BuildStaticVariant() bool { func (mod *Module) BuildStaticVariant() bool {