Merge changes I0bf0c186,I859cd636,Ie438d7a7,I30f82aea into main
* changes:
Add and use staticLibrary()
Convert WalkPayloadDeps from blueprint.Module to android.Module
Remove AlwaysRequireApexVariantTag
Move transition code to transition.go
diff --git a/android/Android.bp b/android/Android.bp
index dfea8f9..20cd28b 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -109,6 +109,7 @@
"test_asserts.go",
"test_suites.go",
"testing.go",
+ "transition.go",
"util.go",
"variable.go",
"vendor_api_levels.go",
@@ -154,6 +155,7 @@
"singleton_module_test.go",
"soong_config_modules_test.go",
"test_suites_test.go",
+ "transition_test.go",
"util_test.go",
"variable_test.go",
"vintf_fragment_test.go",
diff --git a/android/apex.go b/android/apex.go
index db93912..f625baf 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -264,9 +264,6 @@
// Marker interface that identifies dependencies that are excluded from APEX contents.
//
-// Unless the tag also implements the AlwaysRequireApexVariantTag this will prevent an apex variant
-// from being created for the module.
-//
// At the moment the sdk.sdkRequirementsMutator relies on the fact that the existing tags which
// implement this interface do not define dependencies onto members of an sdk_snapshot. If that
// changes then sdk.sdkRequirementsMutator will need fixing.
@@ -277,17 +274,6 @@
ExcludeFromApexContents()
}
-// Marker interface that identifies dependencies that always requires an APEX variant to be created.
-//
-// It is possible for a dependency to require an apex variant but exclude the module from the APEX
-// contents. See sdk.sdkMemberDependencyTag.
-type AlwaysRequireApexVariantTag interface {
- blueprint.DependencyTag
-
- // Return true if this tag requires that the target dependency has an apex variant.
- AlwaysRequireApexVariant() bool
-}
-
// Interface that identifies dependencies to skip Apex dependency check
type SkipApexAllowedDependenciesCheck interface {
// Returns true to skip the Apex dependency check, which limits the allowed dependency in build.
@@ -778,7 +764,7 @@
// Function called while walking an APEX's payload dependencies.
//
// Return true if the `to` module should be visited, false otherwise.
-type PayloadDepsCallback func(ctx BaseModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool
+type PayloadDepsCallback func(ctx BaseModuleContext, from Module, to ApexModule, externalDep bool) bool
type WalkPayloadDepsFunc func(ctx BaseModuleContext, do PayloadDepsCallback)
// ModuleWithMinSdkVersionCheck represents a module that implements min_sdk_version checks
@@ -806,7 +792,7 @@
return
}
- walk(ctx, func(ctx BaseModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool {
+ walk(ctx, func(ctx BaseModuleContext, from Module, to ApexModule, externalDep bool) bool {
if externalDep {
// external deps are outside the payload boundary, which is "stable"
// interface. We don't have to check min_sdk_version for external
diff --git a/android/mutator.go b/android/mutator.go
index fdd16a8..1523794 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -337,248 +337,6 @@
return mutator
}
-type IncomingTransitionContext interface {
- ArchModuleContext
- ModuleProviderContext
- ModuleErrorContext
-
- // Module returns the target of the dependency edge for which the transition
- // is being computed
- Module() Module
-
- // Config returns the configuration for the build.
- Config() Config
-
- DeviceConfig() DeviceConfig
-
- // IsAddingDependency returns true if the transition is being called while adding a dependency
- // after the transition mutator has already run, or false if it is being called when the transition
- // mutator is running. This should be used sparingly, all uses will have to be removed in order
- // to support creating variants on demand.
- IsAddingDependency() bool
-}
-
-type OutgoingTransitionContext interface {
- ArchModuleContext
- ModuleProviderContext
-
- // Module returns the target of the dependency edge for which the transition
- // is being computed
- Module() Module
-
- // DepTag() Returns the dependency tag through which this dependency is
- // reached
- DepTag() blueprint.DependencyTag
-
- // Config returns the configuration for the build.
- Config() Config
-
- DeviceConfig() DeviceConfig
-}
-
-// TransitionMutator implements a top-down mechanism where a module tells its
-// direct dependencies what variation they should be built in but the dependency
-// has the final say.
-//
-// When implementing a transition mutator, one needs to implement four methods:
-// - Split() that tells what variations a module has by itself
-// - OutgoingTransition() where a module tells what it wants from its
-// dependency
-// - IncomingTransition() where a module has the final say about its own
-// variation
-// - Mutate() that changes the state of a module depending on its variation
-//
-// That the effective variation of module B when depended on by module A is the
-// composition the outgoing transition of module A and the incoming transition
-// of module B.
-//
-// the outgoing transition should not take the properties of the dependency into
-// account, only those of the module that depends on it. For this reason, the
-// dependency is not even passed into it as an argument. Likewise, the incoming
-// transition should not take the properties of the depending module into
-// account and is thus not informed about it. This makes for a nice
-// decomposition of the decision logic.
-//
-// A given transition mutator only affects its own variation; other variations
-// stay unchanged along the dependency edges.
-//
-// Soong makes sure that all modules are created in the desired variations and
-// that dependency edges are set up correctly. This ensures that "missing
-// variation" errors do not happen and allows for more flexible changes in the
-// value of the variation among dependency edges (as oppposed to bottom-up
-// mutators where if module A in variation X depends on module B and module B
-// has that variation X, A must depend on variation X of B)
-//
-// The limited power of the context objects passed to individual mutators
-// methods also makes it more difficult to shoot oneself in the foot. Complete
-// safety is not guaranteed because no one prevents individual transition
-// mutators from mutating modules in illegal ways and for e.g. Split() or
-// Mutate() to run their own visitations of the transitive dependency of the
-// module and both of these are bad ideas, but it's better than no guardrails at
-// all.
-//
-// This model is pretty close to Bazel's configuration transitions. The mapping
-// between concepts in Soong and Bazel is as follows:
-// - Module == configured target
-// - Variant == configuration
-// - Variation name == configuration flag
-// - Variation == configuration flag value
-// - Outgoing transition == attribute transition
-// - Incoming transition == rule transition
-//
-// The Split() method does not have a Bazel equivalent and Bazel split
-// transitions do not have a Soong equivalent.
-//
-// Mutate() does not make sense in Bazel due to the different models of the
-// two systems: when creating new variations, Soong clones the old module and
-// thus some way is needed to change it state whereas Bazel creates each
-// configuration of a given configured target anew.
-type TransitionMutator interface {
- // Split returns the set of variations that should be created for a module no
- // matter who depends on it. Used when Make depends on a particular variation
- // or when the module knows its variations just based on information given to
- // it in the Blueprint file. This method should not mutate the module it is
- // called on.
- Split(ctx BaseModuleContext) []string
-
- // OutgoingTransition is called on a module to determine which variation it wants
- // from its direct dependencies. The dependency itself can override this decision.
- // This method should not mutate the module itself.
- OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string
-
- // IncomingTransition is called on a module to determine which variation it should
- // be in based on the variation modules that depend on it want. This gives the module
- // a final say about its own variations. This method should not mutate the module
- // itself.
- IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string
-
- // Mutate is called after a module was split into multiple variations on each variation.
- // It should not split the module any further but adding new dependencies is
- // fine. Unlike all the other methods on TransitionMutator, this method is
- // allowed to mutate the module.
- Mutate(ctx BottomUpMutatorContext, variation string)
-}
-
-type androidTransitionMutator struct {
- finalPhase bool
- mutator TransitionMutator
- name string
-}
-
-func (a *androidTransitionMutator) Split(ctx blueprint.BaseModuleContext) []string {
- if a.finalPhase {
- panic("TransitionMutator not allowed in FinalDepsMutators")
- }
- if m, ok := ctx.Module().(Module); ok {
- moduleContext := m.base().baseModuleContextFactory(ctx)
- return a.mutator.Split(&moduleContext)
- } else {
- return []string{""}
- }
-}
-
-type outgoingTransitionContextImpl struct {
- archModuleContext
- bp blueprint.OutgoingTransitionContext
-}
-
-func (c *outgoingTransitionContextImpl) Module() Module {
- return c.bp.Module().(Module)
-}
-
-func (c *outgoingTransitionContextImpl) DepTag() blueprint.DependencyTag {
- return c.bp.DepTag()
-}
-
-func (c *outgoingTransitionContextImpl) Config() Config {
- return c.bp.Config().(Config)
-}
-
-func (c *outgoingTransitionContextImpl) DeviceConfig() DeviceConfig {
- return DeviceConfig{c.bp.Config().(Config).deviceConfig}
-}
-
-func (c *outgoingTransitionContextImpl) provider(provider blueprint.AnyProviderKey) (any, bool) {
- return c.bp.Provider(provider)
-}
-
-func (a *androidTransitionMutator) OutgoingTransition(bpctx blueprint.OutgoingTransitionContext, sourceVariation string) string {
- if m, ok := bpctx.Module().(Module); ok {
- ctx := outgoingTransitionContextPool.Get().(*outgoingTransitionContextImpl)
- defer outgoingTransitionContextPool.Put(ctx)
- *ctx = outgoingTransitionContextImpl{
- archModuleContext: m.base().archModuleContextFactory(bpctx),
- bp: bpctx,
- }
- return a.mutator.OutgoingTransition(ctx, sourceVariation)
- } else {
- return ""
- }
-}
-
-type incomingTransitionContextImpl struct {
- archModuleContext
- bp blueprint.IncomingTransitionContext
-}
-
-func (c *incomingTransitionContextImpl) Module() Module {
- return c.bp.Module().(Module)
-}
-
-func (c *incomingTransitionContextImpl) Config() Config {
- return c.bp.Config().(Config)
-}
-
-func (c *incomingTransitionContextImpl) DeviceConfig() DeviceConfig {
- return DeviceConfig{c.bp.Config().(Config).deviceConfig}
-}
-
-func (c *incomingTransitionContextImpl) IsAddingDependency() bool {
- return c.bp.IsAddingDependency()
-}
-
-func (c *incomingTransitionContextImpl) provider(provider blueprint.AnyProviderKey) (any, bool) {
- return c.bp.Provider(provider)
-}
-
-func (c *incomingTransitionContextImpl) ModuleErrorf(fmt string, args ...interface{}) {
- c.bp.ModuleErrorf(fmt, args)
-}
-
-func (c *incomingTransitionContextImpl) PropertyErrorf(property, fmt string, args ...interface{}) {
- c.bp.PropertyErrorf(property, fmt, args)
-}
-
-func (a *androidTransitionMutator) IncomingTransition(bpctx blueprint.IncomingTransitionContext, incomingVariation string) string {
- if m, ok := bpctx.Module().(Module); ok {
- ctx := incomingTransitionContextPool.Get().(*incomingTransitionContextImpl)
- defer incomingTransitionContextPool.Put(ctx)
- *ctx = incomingTransitionContextImpl{
- archModuleContext: m.base().archModuleContextFactory(bpctx),
- bp: bpctx,
- }
- return a.mutator.IncomingTransition(ctx, incomingVariation)
- } else {
- return ""
- }
-}
-
-func (a *androidTransitionMutator) Mutate(ctx blueprint.BottomUpMutatorContext, variation string) {
- if am, ok := ctx.Module().(Module); ok {
- if variation != "" {
- // TODO: this should really be checking whether the TransitionMutator affected this module, not
- // the empty variant, but TransitionMutator has no concept of skipping a module.
- base := am.base()
- base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, a.name)
- base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variation)
- }
-
- mctx := bottomUpMutatorContextFactory(ctx, am, a.finalPhase)
- defer bottomUpMutatorContextPool.Put(mctx)
- a.mutator.Mutate(mctx, variation)
- }
-}
-
func (x *registerMutatorsContext) Transition(name string, m TransitionMutator) TransitionMutatorHandle {
atm := &androidTransitionMutator{
finalPhase: x.finalPhase,
diff --git a/android/mutator_test.go b/android/mutator_test.go
index 1d5f890..60a6119 100644
--- a/android/mutator_test.go
+++ b/android/mutator_test.go
@@ -83,132 +83,6 @@
AssertDeepEquals(t, "foo missing deps", []string{"added_missing_dep", "regular_missing_dep"}, foo.missingDeps)
}
-type testTransitionMutator struct {
- split func(ctx BaseModuleContext) []string
- outgoingTransition func(ctx OutgoingTransitionContext, sourceVariation string) string
- incomingTransition func(ctx IncomingTransitionContext, incomingVariation string) string
- mutate func(ctx BottomUpMutatorContext, variation string)
-}
-
-func (t *testTransitionMutator) Split(ctx BaseModuleContext) []string {
- if t.split != nil {
- return t.split(ctx)
- }
- return []string{""}
-}
-
-func (t *testTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
- if t.outgoingTransition != nil {
- return t.outgoingTransition(ctx, sourceVariation)
- }
- return sourceVariation
-}
-
-func (t *testTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
- if t.incomingTransition != nil {
- return t.incomingTransition(ctx, incomingVariation)
- }
- return incomingVariation
-}
-
-func (t *testTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
- if t.mutate != nil {
- t.mutate(ctx, variation)
- }
-}
-
-func TestModuleString(t *testing.T) {
- bp := `
- test {
- name: "foo",
- }
- `
-
- var moduleStrings []string
-
- GroupFixturePreparers(
- FixtureRegisterWithContext(func(ctx RegistrationContext) {
-
- ctx.PreArchMutators(func(ctx RegisterMutatorsContext) {
- ctx.Transition("pre_arch", &testTransitionMutator{
- split: func(ctx BaseModuleContext) []string {
- moduleStrings = append(moduleStrings, ctx.Module().String())
- return []string{"a", "b"}
- },
- })
- })
-
- ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
- ctx.Transition("pre_deps", &testTransitionMutator{
- split: func(ctx BaseModuleContext) []string {
- moduleStrings = append(moduleStrings, ctx.Module().String())
- return []string{"c", "d"}
- },
- })
- })
-
- ctx.PostDepsMutators(func(ctx RegisterMutatorsContext) {
- ctx.Transition("post_deps", &testTransitionMutator{
- split: func(ctx BaseModuleContext) []string {
- moduleStrings = append(moduleStrings, ctx.Module().String())
- return []string{"e", "f"}
- },
- outgoingTransition: func(ctx OutgoingTransitionContext, sourceVariation string) string {
- return ""
- },
- })
- ctx.BottomUp("rename_bottom_up", func(ctx BottomUpMutatorContext) {
- moduleStrings = append(moduleStrings, ctx.Module().String())
- ctx.Rename(ctx.Module().base().Name() + "_renamed1")
- }).UsesRename()
- ctx.BottomUp("final", func(ctx BottomUpMutatorContext) {
- moduleStrings = append(moduleStrings, ctx.Module().String())
- })
- })
-
- ctx.RegisterModuleType("test", mutatorTestModuleFactory)
- }),
- FixtureWithRootAndroidBp(bp),
- ).RunTest(t)
-
- want := []string{
- // Initial name.
- "foo{}",
-
- // After pre_arch (reversed because rename_top_down is TopDown so it visits in reverse order).
- "foo{pre_arch:b}",
- "foo{pre_arch:a}",
-
- // After pre_deps (reversed because post_deps TransitionMutator.Split is TopDown).
- "foo{pre_arch:b,pre_deps:d}",
- "foo{pre_arch:b,pre_deps:c}",
- "foo{pre_arch:a,pre_deps:d}",
- "foo{pre_arch:a,pre_deps:c}",
-
- // After post_deps.
- "foo{pre_arch:a,pre_deps:c,post_deps:e}",
- "foo{pre_arch:a,pre_deps:c,post_deps:f}",
- "foo{pre_arch:a,pre_deps:d,post_deps:e}",
- "foo{pre_arch:a,pre_deps:d,post_deps:f}",
- "foo{pre_arch:b,pre_deps:c,post_deps:e}",
- "foo{pre_arch:b,pre_deps:c,post_deps:f}",
- "foo{pre_arch:b,pre_deps:d,post_deps:e}",
- "foo{pre_arch:b,pre_deps:d,post_deps:f}",
-
- // After rename_bottom_up.
- "foo_renamed1{pre_arch:a,pre_deps:c,post_deps:e}",
- "foo_renamed1{pre_arch:a,pre_deps:c,post_deps:f}",
- "foo_renamed1{pre_arch:a,pre_deps:d,post_deps:e}",
- "foo_renamed1{pre_arch:a,pre_deps:d,post_deps:f}",
- "foo_renamed1{pre_arch:b,pre_deps:c,post_deps:e}",
- "foo_renamed1{pre_arch:b,pre_deps:c,post_deps:f}",
- "foo_renamed1{pre_arch:b,pre_deps:d,post_deps:e}",
- "foo_renamed1{pre_arch:b,pre_deps:d,post_deps:f}",
- }
-
- AssertDeepEquals(t, "module String() values", want, moduleStrings)
-}
-
func TestFinalDepsPhase(t *testing.T) {
bp := `
test {
@@ -288,22 +162,3 @@
AssertDeepEquals(t, "final", finalWant, finalGotMap)
}
-
-func TestTransitionMutatorInFinalDeps(t *testing.T) {
- GroupFixturePreparers(
- FixtureRegisterWithContext(func(ctx RegistrationContext) {
- ctx.FinalDepsMutators(func(ctx RegisterMutatorsContext) {
- ctx.Transition("vars", &testTransitionMutator{
- split: func(ctx BaseModuleContext) []string {
- return []string{"a", "b"}
- },
- })
- })
-
- ctx.RegisterModuleType("test", mutatorTestModuleFactory)
- }),
- FixtureWithRootAndroidBp(`test {name: "foo"}`),
- ).
- ExtendWithErrorHandler(FixtureExpectsOneErrorPattern("not allowed in FinalDepsMutators")).
- RunTest(t)
-}
diff --git a/android/transition.go b/android/transition.go
new file mode 100644
index 0000000..7c04eff
--- /dev/null
+++ b/android/transition.go
@@ -0,0 +1,259 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import "github.com/google/blueprint"
+
+// TransitionMutator implements a top-down mechanism where a module tells its
+// direct dependencies what variation they should be built in but the dependency
+// has the final say.
+//
+// When implementing a transition mutator, one needs to implement four methods:
+// - Split() that tells what variations a module has by itself
+// - OutgoingTransition() where a module tells what it wants from its
+// dependency
+// - IncomingTransition() where a module has the final say about its own
+// variation
+// - Mutate() that changes the state of a module depending on its variation
+//
+// That the effective variation of module B when depended on by module A is the
+// composition the outgoing transition of module A and the incoming transition
+// of module B.
+//
+// the outgoing transition should not take the properties of the dependency into
+// account, only those of the module that depends on it. For this reason, the
+// dependency is not even passed into it as an argument. Likewise, the incoming
+// transition should not take the properties of the depending module into
+// account and is thus not informed about it. This makes for a nice
+// decomposition of the decision logic.
+//
+// A given transition mutator only affects its own variation; other variations
+// stay unchanged along the dependency edges.
+//
+// Soong makes sure that all modules are created in the desired variations and
+// that dependency edges are set up correctly. This ensures that "missing
+// variation" errors do not happen and allows for more flexible changes in the
+// value of the variation among dependency edges (as oppposed to bottom-up
+// mutators where if module A in variation X depends on module B and module B
+// has that variation X, A must depend on variation X of B)
+//
+// The limited power of the context objects passed to individual mutators
+// methods also makes it more difficult to shoot oneself in the foot. Complete
+// safety is not guaranteed because no one prevents individual transition
+// mutators from mutating modules in illegal ways and for e.g. Split() or
+// Mutate() to run their own visitations of the transitive dependency of the
+// module and both of these are bad ideas, but it's better than no guardrails at
+// all.
+//
+// This model is pretty close to Bazel's configuration transitions. The mapping
+// between concepts in Soong and Bazel is as follows:
+// - Module == configured target
+// - Variant == configuration
+// - Variation name == configuration flag
+// - Variation == configuration flag value
+// - Outgoing transition == attribute transition
+// - Incoming transition == rule transition
+//
+// The Split() method does not have a Bazel equivalent and Bazel split
+// transitions do not have a Soong equivalent.
+//
+// Mutate() does not make sense in Bazel due to the different models of the
+// two systems: when creating new variations, Soong clones the old module and
+// thus some way is needed to change it state whereas Bazel creates each
+// configuration of a given configured target anew.
+type TransitionMutator interface {
+ // Split returns the set of variations that should be created for a module no
+ // matter who depends on it. Used when Make depends on a particular variation
+ // or when the module knows its variations just based on information given to
+ // it in the Blueprint file. This method should not mutate the module it is
+ // called on.
+ Split(ctx BaseModuleContext) []string
+
+ // OutgoingTransition is called on a module to determine which variation it wants
+ // from its direct dependencies. The dependency itself can override this decision.
+ // This method should not mutate the module itself.
+ OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string
+
+ // IncomingTransition is called on a module to determine which variation it should
+ // be in based on the variation modules that depend on it want. This gives the module
+ // a final say about its own variations. This method should not mutate the module
+ // itself.
+ IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string
+
+ // Mutate is called after a module was split into multiple variations on each variation.
+ // It should not split the module any further but adding new dependencies is
+ // fine. Unlike all the other methods on TransitionMutator, this method is
+ // allowed to mutate the module.
+ Mutate(ctx BottomUpMutatorContext, variation string)
+}
+
+type IncomingTransitionContext interface {
+ ArchModuleContext
+ ModuleProviderContext
+ ModuleErrorContext
+
+ // Module returns the target of the dependency edge for which the transition
+ // is being computed
+ Module() Module
+
+ // Config returns the configuration for the build.
+ Config() Config
+
+ DeviceConfig() DeviceConfig
+
+ // IsAddingDependency returns true if the transition is being called while adding a dependency
+ // after the transition mutator has already run, or false if it is being called when the transition
+ // mutator is running. This should be used sparingly, all uses will have to be removed in order
+ // to support creating variants on demand.
+ IsAddingDependency() bool
+}
+
+type OutgoingTransitionContext interface {
+ ArchModuleContext
+ ModuleProviderContext
+
+ // Module returns the target of the dependency edge for which the transition
+ // is being computed
+ Module() Module
+
+ // DepTag() Returns the dependency tag through which this dependency is
+ // reached
+ DepTag() blueprint.DependencyTag
+
+ // Config returns the configuration for the build.
+ Config() Config
+
+ DeviceConfig() DeviceConfig
+}
+
+type androidTransitionMutator struct {
+ finalPhase bool
+ mutator TransitionMutator
+ name string
+}
+
+func (a *androidTransitionMutator) Split(ctx blueprint.BaseModuleContext) []string {
+ if a.finalPhase {
+ panic("TransitionMutator not allowed in FinalDepsMutators")
+ }
+ if m, ok := ctx.Module().(Module); ok {
+ moduleContext := m.base().baseModuleContextFactory(ctx)
+ return a.mutator.Split(&moduleContext)
+ } else {
+ return []string{""}
+ }
+}
+
+func (a *androidTransitionMutator) OutgoingTransition(bpctx blueprint.OutgoingTransitionContext, sourceVariation string) string {
+ if m, ok := bpctx.Module().(Module); ok {
+ ctx := outgoingTransitionContextPool.Get().(*outgoingTransitionContextImpl)
+ defer outgoingTransitionContextPool.Put(ctx)
+ *ctx = outgoingTransitionContextImpl{
+ archModuleContext: m.base().archModuleContextFactory(bpctx),
+ bp: bpctx,
+ }
+ return a.mutator.OutgoingTransition(ctx, sourceVariation)
+ } else {
+ return ""
+ }
+}
+
+func (a *androidTransitionMutator) IncomingTransition(bpctx blueprint.IncomingTransitionContext, incomingVariation string) string {
+ if m, ok := bpctx.Module().(Module); ok {
+ ctx := incomingTransitionContextPool.Get().(*incomingTransitionContextImpl)
+ defer incomingTransitionContextPool.Put(ctx)
+ *ctx = incomingTransitionContextImpl{
+ archModuleContext: m.base().archModuleContextFactory(bpctx),
+ bp: bpctx,
+ }
+ return a.mutator.IncomingTransition(ctx, incomingVariation)
+ } else {
+ return ""
+ }
+}
+
+func (a *androidTransitionMutator) Mutate(ctx blueprint.BottomUpMutatorContext, variation string) {
+ if am, ok := ctx.Module().(Module); ok {
+ if variation != "" {
+ // TODO: this should really be checking whether the TransitionMutator affected this module, not
+ // the empty variant, but TransitionMutator has no concept of skipping a module.
+ base := am.base()
+ base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, a.name)
+ base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variation)
+ }
+
+ mctx := bottomUpMutatorContextFactory(ctx, am, a.finalPhase)
+ defer bottomUpMutatorContextPool.Put(mctx)
+ a.mutator.Mutate(mctx, variation)
+ }
+}
+
+type incomingTransitionContextImpl struct {
+ archModuleContext
+ bp blueprint.IncomingTransitionContext
+}
+
+func (c *incomingTransitionContextImpl) Module() Module {
+ return c.bp.Module().(Module)
+}
+
+func (c *incomingTransitionContextImpl) Config() Config {
+ return c.bp.Config().(Config)
+}
+
+func (c *incomingTransitionContextImpl) DeviceConfig() DeviceConfig {
+ return DeviceConfig{c.bp.Config().(Config).deviceConfig}
+}
+
+func (c *incomingTransitionContextImpl) IsAddingDependency() bool {
+ return c.bp.IsAddingDependency()
+}
+
+func (c *incomingTransitionContextImpl) provider(provider blueprint.AnyProviderKey) (any, bool) {
+ return c.bp.Provider(provider)
+}
+
+func (c *incomingTransitionContextImpl) ModuleErrorf(fmt string, args ...interface{}) {
+ c.bp.ModuleErrorf(fmt, args)
+}
+
+func (c *incomingTransitionContextImpl) PropertyErrorf(property, fmt string, args ...interface{}) {
+ c.bp.PropertyErrorf(property, fmt, args)
+}
+
+type outgoingTransitionContextImpl struct {
+ archModuleContext
+ bp blueprint.OutgoingTransitionContext
+}
+
+func (c *outgoingTransitionContextImpl) Module() Module {
+ return c.bp.Module().(Module)
+}
+
+func (c *outgoingTransitionContextImpl) DepTag() blueprint.DependencyTag {
+ return c.bp.DepTag()
+}
+
+func (c *outgoingTransitionContextImpl) Config() Config {
+ return c.bp.Config().(Config)
+}
+
+func (c *outgoingTransitionContextImpl) DeviceConfig() DeviceConfig {
+ return DeviceConfig{c.bp.Config().(Config).deviceConfig}
+}
+
+func (c *outgoingTransitionContextImpl) provider(provider blueprint.AnyProviderKey) (any, bool) {
+ return c.bp.Provider(provider)
+}
diff --git a/android/transition_test.go b/android/transition_test.go
new file mode 100644
index 0000000..f7618f3
--- /dev/null
+++ b/android/transition_test.go
@@ -0,0 +1,162 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import "testing"
+
+type testTransitionMutator struct {
+ split func(ctx BaseModuleContext) []string
+ outgoingTransition func(ctx OutgoingTransitionContext, sourceVariation string) string
+ incomingTransition func(ctx IncomingTransitionContext, incomingVariation string) string
+ mutate func(ctx BottomUpMutatorContext, variation string)
+}
+
+func (t *testTransitionMutator) Split(ctx BaseModuleContext) []string {
+ if t.split != nil {
+ return t.split(ctx)
+ }
+ return []string{""}
+}
+
+func (t *testTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
+ if t.outgoingTransition != nil {
+ return t.outgoingTransition(ctx, sourceVariation)
+ }
+ return sourceVariation
+}
+
+func (t *testTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
+ if t.incomingTransition != nil {
+ return t.incomingTransition(ctx, incomingVariation)
+ }
+ return incomingVariation
+}
+
+func (t *testTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
+ if t.mutate != nil {
+ t.mutate(ctx, variation)
+ }
+}
+
+func TestModuleString(t *testing.T) {
+ bp := `
+ test {
+ name: "foo",
+ }
+ `
+
+ var moduleStrings []string
+
+ GroupFixturePreparers(
+ FixtureRegisterWithContext(func(ctx RegistrationContext) {
+
+ ctx.PreArchMutators(func(ctx RegisterMutatorsContext) {
+ ctx.Transition("pre_arch", &testTransitionMutator{
+ split: func(ctx BaseModuleContext) []string {
+ moduleStrings = append(moduleStrings, ctx.Module().String())
+ return []string{"a", "b"}
+ },
+ })
+ })
+
+ ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
+ ctx.Transition("pre_deps", &testTransitionMutator{
+ split: func(ctx BaseModuleContext) []string {
+ moduleStrings = append(moduleStrings, ctx.Module().String())
+ return []string{"c", "d"}
+ },
+ })
+ })
+
+ ctx.PostDepsMutators(func(ctx RegisterMutatorsContext) {
+ ctx.Transition("post_deps", &testTransitionMutator{
+ split: func(ctx BaseModuleContext) []string {
+ moduleStrings = append(moduleStrings, ctx.Module().String())
+ return []string{"e", "f"}
+ },
+ outgoingTransition: func(ctx OutgoingTransitionContext, sourceVariation string) string {
+ return ""
+ },
+ })
+ ctx.BottomUp("rename_bottom_up", func(ctx BottomUpMutatorContext) {
+ moduleStrings = append(moduleStrings, ctx.Module().String())
+ ctx.Rename(ctx.Module().base().Name() + "_renamed1")
+ }).UsesRename()
+ ctx.BottomUp("final", func(ctx BottomUpMutatorContext) {
+ moduleStrings = append(moduleStrings, ctx.Module().String())
+ })
+ })
+
+ ctx.RegisterModuleType("test", mutatorTestModuleFactory)
+ }),
+ FixtureWithRootAndroidBp(bp),
+ ).RunTest(t)
+
+ want := []string{
+ // Initial name.
+ "foo{}",
+
+ // After pre_arch (reversed because rename_top_down is TopDown so it visits in reverse order).
+ "foo{pre_arch:b}",
+ "foo{pre_arch:a}",
+
+ // After pre_deps (reversed because post_deps TransitionMutator.Split is TopDown).
+ "foo{pre_arch:b,pre_deps:d}",
+ "foo{pre_arch:b,pre_deps:c}",
+ "foo{pre_arch:a,pre_deps:d}",
+ "foo{pre_arch:a,pre_deps:c}",
+
+ // After post_deps.
+ "foo{pre_arch:a,pre_deps:c,post_deps:e}",
+ "foo{pre_arch:a,pre_deps:c,post_deps:f}",
+ "foo{pre_arch:a,pre_deps:d,post_deps:e}",
+ "foo{pre_arch:a,pre_deps:d,post_deps:f}",
+ "foo{pre_arch:b,pre_deps:c,post_deps:e}",
+ "foo{pre_arch:b,pre_deps:c,post_deps:f}",
+ "foo{pre_arch:b,pre_deps:d,post_deps:e}",
+ "foo{pre_arch:b,pre_deps:d,post_deps:f}",
+
+ // After rename_bottom_up.
+ "foo_renamed1{pre_arch:a,pre_deps:c,post_deps:e}",
+ "foo_renamed1{pre_arch:a,pre_deps:c,post_deps:f}",
+ "foo_renamed1{pre_arch:a,pre_deps:d,post_deps:e}",
+ "foo_renamed1{pre_arch:a,pre_deps:d,post_deps:f}",
+ "foo_renamed1{pre_arch:b,pre_deps:c,post_deps:e}",
+ "foo_renamed1{pre_arch:b,pre_deps:c,post_deps:f}",
+ "foo_renamed1{pre_arch:b,pre_deps:d,post_deps:e}",
+ "foo_renamed1{pre_arch:b,pre_deps:d,post_deps:f}",
+ }
+
+ AssertDeepEquals(t, "module String() values", want, moduleStrings)
+}
+
+func TestTransitionMutatorInFinalDeps(t *testing.T) {
+ GroupFixturePreparers(
+ FixtureRegisterWithContext(func(ctx RegistrationContext) {
+ ctx.FinalDepsMutators(func(ctx RegisterMutatorsContext) {
+ ctx.Transition("vars", &testTransitionMutator{
+ split: func(ctx BaseModuleContext) []string {
+ return []string{"a", "b"}
+ },
+ })
+ })
+
+ ctx.RegisterModuleType("test", mutatorTestModuleFactory)
+ }),
+ FixtureWithRootAndroidBp(`test {name: "foo"}`),
+ ).
+ ExtendWithErrorHandler(FixtureExpectsOneErrorPattern("not allowed in FinalDepsMutators")).
+ RunTest(t)
+}
diff --git a/apex/apex.go b/apex/apex.go
index 5f700ee..e22cf9e 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -973,21 +973,8 @@
if !ok || !am.CanHaveApexVariants() {
return false
}
- depTag := mctx.OtherModuleDependencyTag(child)
- // Check to see if the tag always requires that the child module has an apex variant for every
- // apex variant of the parent module. If it does not then it is still possible for something
- // else, e.g. the DepIsInSameApex(...) method to decide that a variant is required.
- if required, ok := depTag.(android.AlwaysRequireApexVariantTag); ok && required.AlwaysRequireApexVariant() {
- return true
- }
- if !android.IsDepInSameApex(mctx, parent, child) {
- return false
- }
-
- // By default, all the transitive dependencies are collected, unless filtered out
- // above.
- return true
+ return android.IsDepInSameApex(mctx, parent, child)
}
android.SetProvider(mctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{})
@@ -2707,7 +2694,7 @@
return
}
- a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+ a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from android.Module, to android.ApexModule, externalDep bool) bool {
// As soon as the dependency graph crosses the APEX boundary, don't go further.
if externalDep {
return false
diff --git a/cc/afdo.go b/cc/afdo.go
index 14d105e..03dc271 100644
--- a/cc/afdo.go
+++ b/cc/afdo.go
@@ -163,7 +163,7 @@
}
// TODO(b/324141705): this is designed to prevent propagating AFDO from static libraries that have afdo: true set, but
- // it should be m.static() && !m.staticBinary() so that static binaries use AFDO variants of dependencies.
+ // it should be m.staticLibrary() so that static binaries use AFDO variants of dependencies.
if m.static() {
return ""
}
@@ -188,7 +188,7 @@
if variation == "" {
// The empty variation is either a module that has enabled AFDO for itself, or the non-AFDO
// variant of a dependency.
- if m.afdo.afdoEnabled() && !(m.static() && !m.staticBinary()) && !m.Host() {
+ if m.afdo.afdoEnabled() && !m.staticLibrary() && !m.Host() {
m.afdo.addDep(ctx, ctx.ModuleName())
}
} else {
diff --git a/cc/cc.go b/cc/cc.go
index 4838a5f..8023324 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -519,6 +519,7 @@
type ModuleContextIntf interface {
static() bool
staticBinary() bool
+ staticLibrary() bool
testBinary() bool
testLibrary() bool
header() bool
@@ -1523,6 +1524,10 @@
return ctx.mod.staticBinary()
}
+func (ctx *moduleContextImpl) staticLibrary() bool {
+ return ctx.mod.staticLibrary()
+}
+
func (ctx *moduleContextImpl) testBinary() bool {
return ctx.mod.testBinary()
}
@@ -3550,6 +3555,15 @@
return false
}
+func (c *Module) staticLibrary() bool {
+ if static, ok := c.linker.(interface {
+ staticLibrary() bool
+ }); ok {
+ return static.staticLibrary()
+ }
+ return false
+}
+
func (c *Module) staticBinary() bool {
if static, ok := c.linker.(interface {
staticBinary() bool
diff --git a/cc/coverage.go b/cc/coverage.go
index a7618dd..dbb424f 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -145,7 +145,7 @@
// Even if we don't have coverage enabled, if any of our object files were compiled
// with coverage, then we need to add --coverage to our ldflags.
if !cov.linkCoverage {
- if ctx.static() && !ctx.staticBinary() {
+ if ctx.staticLibrary() {
// For static libraries, the only thing that changes our object files
// are included whole static libraries, so check to see if any of
// those have coverage enabled.
diff --git a/cc/library.go b/cc/library.go
index ea87946..6485ea3 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1800,12 +1800,17 @@
return library.shared() || library.static()
}
-// static returns true if this library is for a "static' variant.
+// static returns true if this library is for a "static" variant.
func (library *libraryDecorator) static() bool {
return library.MutatedProperties.VariantIsStatic
}
-// shared returns true if this library is for a "shared' variant.
+// staticLibrary returns true if this library is for a "static"" variant.
+func (library *libraryDecorator) staticLibrary() bool {
+ return library.static()
+}
+
+// shared returns true if this library is for a "shared" variant.
func (library *libraryDecorator) shared() bool {
return library.MutatedProperties.VariantIsShared
}
diff --git a/cc/orderfile.go b/cc/orderfile.go
index 6e08da7..c07a098 100644
--- a/cc/orderfile.go
+++ b/cc/orderfile.go
@@ -153,7 +153,7 @@
}
// Currently, we are not enabling orderfiles to begin from static libraries
- if ctx.static() && !ctx.staticBinary() {
+ if ctx.staticLibrary() {
return
}
diff --git a/java/app.go b/java/app.go
index bedb45c..276e960 100644
--- a/java/app.go
+++ b/java/app.go
@@ -1225,7 +1225,7 @@
}
depsInfo := android.DepNameToDepInfoMap{}
- a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+ a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from android.Module, to android.ApexModule, externalDep bool) bool {
depName := to.Name()
// Skip dependencies that are only available to APEXes; they are developed with updatability