xref: /aosp_15_r20/build/blueprint/transition.go (revision 1fa6dee971e1612fa5cc0aa5ca2d35a22e2c34a3)
1*1fa6dee9SAndroid Build Coastguard Worker// Copyright 2024 Google Inc. All rights reserved.
2*1fa6dee9SAndroid Build Coastguard Worker//
3*1fa6dee9SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*1fa6dee9SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*1fa6dee9SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*1fa6dee9SAndroid Build Coastguard Worker//
7*1fa6dee9SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*1fa6dee9SAndroid Build Coastguard Worker//
9*1fa6dee9SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*1fa6dee9SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*1fa6dee9SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*1fa6dee9SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*1fa6dee9SAndroid Build Coastguard Worker// limitations under the License.
14*1fa6dee9SAndroid Build Coastguard Worker
15*1fa6dee9SAndroid Build Coastguard Workerpackage blueprint
16*1fa6dee9SAndroid Build Coastguard Worker
17*1fa6dee9SAndroid Build Coastguard Workerimport (
18*1fa6dee9SAndroid Build Coastguard Worker	"fmt"
19*1fa6dee9SAndroid Build Coastguard Worker	"slices"
20*1fa6dee9SAndroid Build Coastguard Worker	"sort"
21*1fa6dee9SAndroid Build Coastguard Worker)
22*1fa6dee9SAndroid Build Coastguard Worker
23*1fa6dee9SAndroid Build Coastguard Worker// TransitionMutator implements a top-down mechanism where a module tells its
24*1fa6dee9SAndroid Build Coastguard Worker// direct dependencies what variation they should be built in but the dependency
25*1fa6dee9SAndroid Build Coastguard Worker// has the final say.
26*1fa6dee9SAndroid Build Coastguard Worker//
27*1fa6dee9SAndroid Build Coastguard Worker// When implementing a transition mutator, one needs to implement four methods:
28*1fa6dee9SAndroid Build Coastguard Worker//   - Split() that tells what variations a module has by itself
29*1fa6dee9SAndroid Build Coastguard Worker//   - OutgoingTransition() where a module tells what it wants from its
30*1fa6dee9SAndroid Build Coastguard Worker//     dependency
31*1fa6dee9SAndroid Build Coastguard Worker//   - IncomingTransition() where a module has the final say about its own
32*1fa6dee9SAndroid Build Coastguard Worker//     variation
33*1fa6dee9SAndroid Build Coastguard Worker//   - Mutate() that changes the state of a module depending on its variation
34*1fa6dee9SAndroid Build Coastguard Worker//
35*1fa6dee9SAndroid Build Coastguard Worker// That the effective variation of module B when depended on by module A is the
36*1fa6dee9SAndroid Build Coastguard Worker// composition the outgoing transition of module A and the incoming transition
37*1fa6dee9SAndroid Build Coastguard Worker// of module B.
38*1fa6dee9SAndroid Build Coastguard Worker//
39*1fa6dee9SAndroid Build Coastguard Worker// The outgoing transition should not take the properties of the dependency into
40*1fa6dee9SAndroid Build Coastguard Worker// account, only those of the module that depends on it. For this reason, the
41*1fa6dee9SAndroid Build Coastguard Worker// dependency is not even passed into it as an argument. Likewise, the incoming
42*1fa6dee9SAndroid Build Coastguard Worker// transition should not take the properties of the depending module into
43*1fa6dee9SAndroid Build Coastguard Worker// account and is thus not informed about it. This makes for a nice
44*1fa6dee9SAndroid Build Coastguard Worker// decomposition of the decision logic.
45*1fa6dee9SAndroid Build Coastguard Worker//
46*1fa6dee9SAndroid Build Coastguard Worker// A given transition mutator only affects its own variation; other variations
47*1fa6dee9SAndroid Build Coastguard Worker// stay unchanged along the dependency edges.
48*1fa6dee9SAndroid Build Coastguard Worker//
49*1fa6dee9SAndroid Build Coastguard Worker// Soong makes sure that all modules are created in the desired variations and
50*1fa6dee9SAndroid Build Coastguard Worker// that dependency edges are set up correctly. This ensures that "missing
51*1fa6dee9SAndroid Build Coastguard Worker// variation" errors do not happen and allows for more flexible changes in the
52*1fa6dee9SAndroid Build Coastguard Worker// value of the variation among dependency edges (as opposed to bottom-up
53*1fa6dee9SAndroid Build Coastguard Worker// mutators where if module A in variation X depends on module B and module B
54*1fa6dee9SAndroid Build Coastguard Worker// has that variation X, A must depend on variation X of B)
55*1fa6dee9SAndroid Build Coastguard Worker//
56*1fa6dee9SAndroid Build Coastguard Worker// The limited power of the context objects passed to individual mutators
57*1fa6dee9SAndroid Build Coastguard Worker// methods also makes it more difficult to shoot oneself in the foot. Complete
58*1fa6dee9SAndroid Build Coastguard Worker// safety is not guaranteed because no one prevents individual transition
59*1fa6dee9SAndroid Build Coastguard Worker// mutators from mutating modules in illegal ways and for e.g. Split() or
60*1fa6dee9SAndroid Build Coastguard Worker// Mutate() to run their own visitations of the transitive dependency of the
61*1fa6dee9SAndroid Build Coastguard Worker// module and both of these are bad ideas, but it's better than no guardrails at
62*1fa6dee9SAndroid Build Coastguard Worker// all.
63*1fa6dee9SAndroid Build Coastguard Worker//
64*1fa6dee9SAndroid Build Coastguard Worker// This model is pretty close to Bazel's configuration transitions. The mapping
65*1fa6dee9SAndroid Build Coastguard Worker// between concepts in Soong and Bazel is as follows:
66*1fa6dee9SAndroid Build Coastguard Worker//   - Module == configured target
67*1fa6dee9SAndroid Build Coastguard Worker//   - Variant == configuration
68*1fa6dee9SAndroid Build Coastguard Worker//   - Variation name == configuration flag
69*1fa6dee9SAndroid Build Coastguard Worker//   - Variation == configuration flag value
70*1fa6dee9SAndroid Build Coastguard Worker//   - Outgoing transition == attribute transition
71*1fa6dee9SAndroid Build Coastguard Worker//   - Incoming transition == rule transition
72*1fa6dee9SAndroid Build Coastguard Worker//
73*1fa6dee9SAndroid Build Coastguard Worker// The Split() method does not have a Bazel equivalent and Bazel split
74*1fa6dee9SAndroid Build Coastguard Worker// transitions do not have a Soong equivalent.
75*1fa6dee9SAndroid Build Coastguard Worker//
76*1fa6dee9SAndroid Build Coastguard Worker// Mutate() does not make sense in Bazel due to the different models of the
77*1fa6dee9SAndroid Build Coastguard Worker// two systems: when creating new variations, Soong clones the old module and
78*1fa6dee9SAndroid Build Coastguard Worker// thus some way is needed to change it state whereas Bazel creates each
79*1fa6dee9SAndroid Build Coastguard Worker// configuration of a given configured target anew.
80*1fa6dee9SAndroid Build Coastguard Workertype TransitionMutator interface {
81*1fa6dee9SAndroid Build Coastguard Worker	// Split returns the set of variations that should be created for a module no matter
82*1fa6dee9SAndroid Build Coastguard Worker	// who depends on it. Used when Make depends on a particular variation or when
83*1fa6dee9SAndroid Build Coastguard Worker	// the module knows its variations just based on information given to it in
84*1fa6dee9SAndroid Build Coastguard Worker	// the Blueprint file. This method should not mutate the module it is called
85*1fa6dee9SAndroid Build Coastguard Worker	// on.
86*1fa6dee9SAndroid Build Coastguard Worker	Split(ctx BaseModuleContext) []string
87*1fa6dee9SAndroid Build Coastguard Worker
88*1fa6dee9SAndroid Build Coastguard Worker	// OutgoingTransition is called on a module to determine which variation it wants
89*1fa6dee9SAndroid Build Coastguard Worker	// from its direct dependencies. The dependency itself can override this decision.
90*1fa6dee9SAndroid Build Coastguard Worker	// This method should not mutate the module itself.
91*1fa6dee9SAndroid Build Coastguard Worker	OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string
92*1fa6dee9SAndroid Build Coastguard Worker
93*1fa6dee9SAndroid Build Coastguard Worker	// IncomingTransition is called on a module to determine which variation it should
94*1fa6dee9SAndroid Build Coastguard Worker	// be in based on the variation modules that depend on it want. This gives the module
95*1fa6dee9SAndroid Build Coastguard Worker	// a final say about its own variations. This method should not mutate the module
96*1fa6dee9SAndroid Build Coastguard Worker	// itself.
97*1fa6dee9SAndroid Build Coastguard Worker	IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string
98*1fa6dee9SAndroid Build Coastguard Worker
99*1fa6dee9SAndroid Build Coastguard Worker	// Mutate is called after a module was split into multiple variations on each
100*1fa6dee9SAndroid Build Coastguard Worker	// variation.  It should not split the module any further but adding new dependencies
101*1fa6dee9SAndroid Build Coastguard Worker	// is fine. Unlike all the other methods on TransitionMutator, this method is
102*1fa6dee9SAndroid Build Coastguard Worker	// allowed to mutate the module.
103*1fa6dee9SAndroid Build Coastguard Worker	Mutate(ctx BottomUpMutatorContext, variation string)
104*1fa6dee9SAndroid Build Coastguard Worker}
105*1fa6dee9SAndroid Build Coastguard Worker
106*1fa6dee9SAndroid Build Coastguard Workertype IncomingTransitionContext interface {
107*1fa6dee9SAndroid Build Coastguard Worker	// Module returns the target of the dependency edge for which the transition
108*1fa6dee9SAndroid Build Coastguard Worker	// is being computed
109*1fa6dee9SAndroid Build Coastguard Worker	Module() Module
110*1fa6dee9SAndroid Build Coastguard Worker
111*1fa6dee9SAndroid Build Coastguard Worker	// Config returns the config object that was passed to
112*1fa6dee9SAndroid Build Coastguard Worker	// Context.PrepareBuildActions.
113*1fa6dee9SAndroid Build Coastguard Worker	Config() interface{}
114*1fa6dee9SAndroid Build Coastguard Worker
115*1fa6dee9SAndroid Build Coastguard Worker	// Provider returns the value for a provider for the target of the dependency edge for which the
116*1fa6dee9SAndroid Build Coastguard Worker	// transition is being computed.  If the value is not set it returns nil and false.  It panics if
117*1fa6dee9SAndroid Build Coastguard Worker	// called  before the appropriate mutator or GenerateBuildActions pass for the provider.  The value
118*1fa6dee9SAndroid Build Coastguard Worker	// returned may be a deep copy of the value originally passed to SetProvider.
119*1fa6dee9SAndroid Build Coastguard Worker	//
120*1fa6dee9SAndroid Build Coastguard Worker	// This method shouldn't be used directly, prefer the type-safe android.ModuleProvider instead.
121*1fa6dee9SAndroid Build Coastguard Worker	Provider(provider AnyProviderKey) (any, bool)
122*1fa6dee9SAndroid Build Coastguard Worker
123*1fa6dee9SAndroid Build Coastguard Worker	// IsAddingDependency returns true if the transition is being called while adding a dependency
124*1fa6dee9SAndroid Build Coastguard Worker	// after the transition mutator has already run, or false if it is being called when the transition
125*1fa6dee9SAndroid Build Coastguard Worker	// mutator is running.  This should be used sparingly, all uses will have to be removed in order
126*1fa6dee9SAndroid Build Coastguard Worker	// to support creating variants on demand.
127*1fa6dee9SAndroid Build Coastguard Worker	IsAddingDependency() bool
128*1fa6dee9SAndroid Build Coastguard Worker
129*1fa6dee9SAndroid Build Coastguard Worker	// ModuleErrorf reports an error at the line number of the module type in the module definition.
130*1fa6dee9SAndroid Build Coastguard Worker	ModuleErrorf(fmt string, args ...interface{})
131*1fa6dee9SAndroid Build Coastguard Worker
132*1fa6dee9SAndroid Build Coastguard Worker	// PropertyErrorf reports an error at the line number of a property in the module definition.
133*1fa6dee9SAndroid Build Coastguard Worker	PropertyErrorf(property, fmt string, args ...interface{})
134*1fa6dee9SAndroid Build Coastguard Worker}
135*1fa6dee9SAndroid Build Coastguard Worker
136*1fa6dee9SAndroid Build Coastguard Workertype OutgoingTransitionContext interface {
137*1fa6dee9SAndroid Build Coastguard Worker	// Module returns the source of the dependency edge for which the transition
138*1fa6dee9SAndroid Build Coastguard Worker	// is being computed
139*1fa6dee9SAndroid Build Coastguard Worker	Module() Module
140*1fa6dee9SAndroid Build Coastguard Worker
141*1fa6dee9SAndroid Build Coastguard Worker	// DepTag() Returns the dependency tag through which this dependency is
142*1fa6dee9SAndroid Build Coastguard Worker	// reached
143*1fa6dee9SAndroid Build Coastguard Worker	DepTag() DependencyTag
144*1fa6dee9SAndroid Build Coastguard Worker
145*1fa6dee9SAndroid Build Coastguard Worker	// Config returns the config object that was passed to
146*1fa6dee9SAndroid Build Coastguard Worker	// Context.PrepareBuildActions.
147*1fa6dee9SAndroid Build Coastguard Worker	Config() interface{}
148*1fa6dee9SAndroid Build Coastguard Worker
149*1fa6dee9SAndroid Build Coastguard Worker	// Provider returns the value for a provider for the source of the dependency edge for which the
150*1fa6dee9SAndroid Build Coastguard Worker	// transition is being computed.  If the value is not set it returns nil and false.  It panics if
151*1fa6dee9SAndroid Build Coastguard Worker	// called before the appropriate mutator or GenerateBuildActions pass for the provider.  The value
152*1fa6dee9SAndroid Build Coastguard Worker	// returned may be a deep copy of the value originally passed to SetProvider.
153*1fa6dee9SAndroid Build Coastguard Worker	//
154*1fa6dee9SAndroid Build Coastguard Worker	// This method shouldn't be used directly, prefer the type-safe android.ModuleProvider instead.
155*1fa6dee9SAndroid Build Coastguard Worker	Provider(provider AnyProviderKey) (any, bool)
156*1fa6dee9SAndroid Build Coastguard Worker
157*1fa6dee9SAndroid Build Coastguard Worker	// ModuleErrorf reports an error at the line number of the module type in the module definition.
158*1fa6dee9SAndroid Build Coastguard Worker	ModuleErrorf(fmt string, args ...interface{})
159*1fa6dee9SAndroid Build Coastguard Worker
160*1fa6dee9SAndroid Build Coastguard Worker	// PropertyErrorf reports an error at the line number of a property in the module definition.
161*1fa6dee9SAndroid Build Coastguard Worker	PropertyErrorf(property, fmt string, args ...interface{})
162*1fa6dee9SAndroid Build Coastguard Worker}
163*1fa6dee9SAndroid Build Coastguard Worker
164*1fa6dee9SAndroid Build Coastguard Workertype transitionMutatorImpl struct {
165*1fa6dee9SAndroid Build Coastguard Worker	name                        string
166*1fa6dee9SAndroid Build Coastguard Worker	mutator                     TransitionMutator
167*1fa6dee9SAndroid Build Coastguard Worker	variantCreatingMutatorIndex int
168*1fa6dee9SAndroid Build Coastguard Worker	inputVariants               map[*moduleGroup][]*moduleInfo
169*1fa6dee9SAndroid Build Coastguard Worker}
170*1fa6dee9SAndroid Build Coastguard Worker
171*1fa6dee9SAndroid Build Coastguard Worker// Adds each argument in items to l if it's not already there.
172*1fa6dee9SAndroid Build Coastguard Workerfunc addToStringListIfNotPresent(l []string, items ...string) []string {
173*1fa6dee9SAndroid Build Coastguard Worker	for _, i := range items {
174*1fa6dee9SAndroid Build Coastguard Worker		if !slices.Contains(l, i) {
175*1fa6dee9SAndroid Build Coastguard Worker			l = append(l, i)
176*1fa6dee9SAndroid Build Coastguard Worker		}
177*1fa6dee9SAndroid Build Coastguard Worker	}
178*1fa6dee9SAndroid Build Coastguard Worker
179*1fa6dee9SAndroid Build Coastguard Worker	return l
180*1fa6dee9SAndroid Build Coastguard Worker}
181*1fa6dee9SAndroid Build Coastguard Worker
182*1fa6dee9SAndroid Build Coastguard Workerfunc (t *transitionMutatorImpl) addRequiredVariation(m *moduleInfo, variation string) {
183*1fa6dee9SAndroid Build Coastguard Worker	m.requiredVariationsLock.Lock()
184*1fa6dee9SAndroid Build Coastguard Worker	defer m.requiredVariationsLock.Unlock()
185*1fa6dee9SAndroid Build Coastguard Worker
186*1fa6dee9SAndroid Build Coastguard Worker	// This is only a consistency check. Leaking the variations of a transition
187*1fa6dee9SAndroid Build Coastguard Worker	// mutator to another one could well lead to issues that are difficult to
188*1fa6dee9SAndroid Build Coastguard Worker	// track down.
189*1fa6dee9SAndroid Build Coastguard Worker	if m.currentTransitionMutator != "" && m.currentTransitionMutator != t.name {
190*1fa6dee9SAndroid Build Coastguard Worker		panic(fmt.Errorf("transition mutator is %s in mutator %s", m.currentTransitionMutator, t.name))
191*1fa6dee9SAndroid Build Coastguard Worker	}
192*1fa6dee9SAndroid Build Coastguard Worker
193*1fa6dee9SAndroid Build Coastguard Worker	m.currentTransitionMutator = t.name
194*1fa6dee9SAndroid Build Coastguard Worker	m.transitionVariations = addToStringListIfNotPresent(m.transitionVariations, variation)
195*1fa6dee9SAndroid Build Coastguard Worker}
196*1fa6dee9SAndroid Build Coastguard Worker
197*1fa6dee9SAndroid Build Coastguard Workerfunc (t *transitionMutatorImpl) topDownMutator(mctx TopDownMutatorContext) {
198*1fa6dee9SAndroid Build Coastguard Worker	module := mctx.(*mutatorContext).module
199*1fa6dee9SAndroid Build Coastguard Worker	mutatorSplits := t.mutator.Split(mctx)
200*1fa6dee9SAndroid Build Coastguard Worker	if mutatorSplits == nil || len(mutatorSplits) == 0 {
201*1fa6dee9SAndroid Build Coastguard Worker		panic(fmt.Errorf("transition mutator %s returned no splits for module %s", t.name, mctx.ModuleName()))
202*1fa6dee9SAndroid Build Coastguard Worker	}
203*1fa6dee9SAndroid Build Coastguard Worker
204*1fa6dee9SAndroid Build Coastguard Worker	// transitionVariations for given a module can be mutated by the module itself
205*1fa6dee9SAndroid Build Coastguard Worker	// and modules that directly depend on it. Since this is a top-down mutator,
206*1fa6dee9SAndroid Build Coastguard Worker	// all modules that directly depend on this module have already been processed
207*1fa6dee9SAndroid Build Coastguard Worker	// so no locking is necessary.
208*1fa6dee9SAndroid Build Coastguard Worker	// Sort the module transitions, but keep the mutatorSplits in the order returned
209*1fa6dee9SAndroid Build Coastguard Worker	// by Split, as the order can be significant when inter-variant dependencies are
210*1fa6dee9SAndroid Build Coastguard Worker	// used.
211*1fa6dee9SAndroid Build Coastguard Worker	sort.Strings(module.transitionVariations)
212*1fa6dee9SAndroid Build Coastguard Worker	module.transitionVariations = addToStringListIfNotPresent(mutatorSplits, module.transitionVariations...)
213*1fa6dee9SAndroid Build Coastguard Worker
214*1fa6dee9SAndroid Build Coastguard Worker	outgoingTransitionCache := make([][]string, len(module.transitionVariations))
215*1fa6dee9SAndroid Build Coastguard Worker	for srcVariationIndex, srcVariation := range module.transitionVariations {
216*1fa6dee9SAndroid Build Coastguard Worker		srcVariationTransitionCache := make([]string, len(module.directDeps))
217*1fa6dee9SAndroid Build Coastguard Worker		for depIndex, dep := range module.directDeps {
218*1fa6dee9SAndroid Build Coastguard Worker			finalVariation := t.transition(mctx)(mctx.moduleInfo(), srcVariation, dep.module, dep.tag)
219*1fa6dee9SAndroid Build Coastguard Worker			srcVariationTransitionCache[depIndex] = finalVariation
220*1fa6dee9SAndroid Build Coastguard Worker			t.addRequiredVariation(dep.module, finalVariation)
221*1fa6dee9SAndroid Build Coastguard Worker		}
222*1fa6dee9SAndroid Build Coastguard Worker		outgoingTransitionCache[srcVariationIndex] = srcVariationTransitionCache
223*1fa6dee9SAndroid Build Coastguard Worker	}
224*1fa6dee9SAndroid Build Coastguard Worker	module.outgoingTransitionCache = outgoingTransitionCache
225*1fa6dee9SAndroid Build Coastguard Worker}
226*1fa6dee9SAndroid Build Coastguard Worker
227*1fa6dee9SAndroid Build Coastguard Workertype transitionContextImpl struct {
228*1fa6dee9SAndroid Build Coastguard Worker	context     *Context
229*1fa6dee9SAndroid Build Coastguard Worker	source      *moduleInfo
230*1fa6dee9SAndroid Build Coastguard Worker	dep         *moduleInfo
231*1fa6dee9SAndroid Build Coastguard Worker	depTag      DependencyTag
232*1fa6dee9SAndroid Build Coastguard Worker	postMutator bool
233*1fa6dee9SAndroid Build Coastguard Worker	config      interface{}
234*1fa6dee9SAndroid Build Coastguard Worker	errs        []error
235*1fa6dee9SAndroid Build Coastguard Worker}
236*1fa6dee9SAndroid Build Coastguard Worker
237*1fa6dee9SAndroid Build Coastguard Workerfunc (c *transitionContextImpl) DepTag() DependencyTag {
238*1fa6dee9SAndroid Build Coastguard Worker	return c.depTag
239*1fa6dee9SAndroid Build Coastguard Worker}
240*1fa6dee9SAndroid Build Coastguard Worker
241*1fa6dee9SAndroid Build Coastguard Workerfunc (c *transitionContextImpl) Config() interface{} {
242*1fa6dee9SAndroid Build Coastguard Worker	return c.config
243*1fa6dee9SAndroid Build Coastguard Worker}
244*1fa6dee9SAndroid Build Coastguard Worker
245*1fa6dee9SAndroid Build Coastguard Workerfunc (c *transitionContextImpl) IsAddingDependency() bool {
246*1fa6dee9SAndroid Build Coastguard Worker	return c.postMutator
247*1fa6dee9SAndroid Build Coastguard Worker}
248*1fa6dee9SAndroid Build Coastguard Worker
249*1fa6dee9SAndroid Build Coastguard Workerfunc (c *transitionContextImpl) error(err error) {
250*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
251*1fa6dee9SAndroid Build Coastguard Worker		c.errs = append(c.errs, err)
252*1fa6dee9SAndroid Build Coastguard Worker	}
253*1fa6dee9SAndroid Build Coastguard Worker}
254*1fa6dee9SAndroid Build Coastguard Worker
255*1fa6dee9SAndroid Build Coastguard Workerfunc (c *transitionContextImpl) ModuleErrorf(fmt string, args ...interface{}) {
256*1fa6dee9SAndroid Build Coastguard Worker	c.error(c.context.moduleErrorf(c.dep, fmt, args...))
257*1fa6dee9SAndroid Build Coastguard Worker}
258*1fa6dee9SAndroid Build Coastguard Worker
259*1fa6dee9SAndroid Build Coastguard Workerfunc (c *transitionContextImpl) PropertyErrorf(property, fmt string, args ...interface{}) {
260*1fa6dee9SAndroid Build Coastguard Worker	c.error(c.context.PropertyErrorf(c.dep.logicModule, property, fmt, args...))
261*1fa6dee9SAndroid Build Coastguard Worker}
262*1fa6dee9SAndroid Build Coastguard Worker
263*1fa6dee9SAndroid Build Coastguard Workertype outgoingTransitionContextImpl struct {
264*1fa6dee9SAndroid Build Coastguard Worker	transitionContextImpl
265*1fa6dee9SAndroid Build Coastguard Worker}
266*1fa6dee9SAndroid Build Coastguard Worker
267*1fa6dee9SAndroid Build Coastguard Workerfunc (c *outgoingTransitionContextImpl) Module() Module {
268*1fa6dee9SAndroid Build Coastguard Worker	return c.source.logicModule
269*1fa6dee9SAndroid Build Coastguard Worker}
270*1fa6dee9SAndroid Build Coastguard Worker
271*1fa6dee9SAndroid Build Coastguard Workerfunc (c *outgoingTransitionContextImpl) Provider(provider AnyProviderKey) (any, bool) {
272*1fa6dee9SAndroid Build Coastguard Worker	return c.context.provider(c.source, provider.provider())
273*1fa6dee9SAndroid Build Coastguard Worker}
274*1fa6dee9SAndroid Build Coastguard Worker
275*1fa6dee9SAndroid Build Coastguard Workertype incomingTransitionContextImpl struct {
276*1fa6dee9SAndroid Build Coastguard Worker	transitionContextImpl
277*1fa6dee9SAndroid Build Coastguard Worker}
278*1fa6dee9SAndroid Build Coastguard Worker
279*1fa6dee9SAndroid Build Coastguard Workerfunc (c *incomingTransitionContextImpl) Module() Module {
280*1fa6dee9SAndroid Build Coastguard Worker	return c.dep.logicModule
281*1fa6dee9SAndroid Build Coastguard Worker}
282*1fa6dee9SAndroid Build Coastguard Worker
283*1fa6dee9SAndroid Build Coastguard Workerfunc (c *incomingTransitionContextImpl) Provider(provider AnyProviderKey) (any, bool) {
284*1fa6dee9SAndroid Build Coastguard Worker	return c.context.provider(c.dep, provider.provider())
285*1fa6dee9SAndroid Build Coastguard Worker}
286*1fa6dee9SAndroid Build Coastguard Worker
287*1fa6dee9SAndroid Build Coastguard Workerfunc (t *transitionMutatorImpl) transition(mctx BaseModuleContext) Transition {
288*1fa6dee9SAndroid Build Coastguard Worker	return func(source *moduleInfo, sourceVariation string, dep *moduleInfo, depTag DependencyTag) string {
289*1fa6dee9SAndroid Build Coastguard Worker		tc := transitionContextImpl{
290*1fa6dee9SAndroid Build Coastguard Worker			context: mctx.base().context,
291*1fa6dee9SAndroid Build Coastguard Worker			source:  source,
292*1fa6dee9SAndroid Build Coastguard Worker			dep:     dep,
293*1fa6dee9SAndroid Build Coastguard Worker			depTag:  depTag,
294*1fa6dee9SAndroid Build Coastguard Worker			config:  mctx.Config(),
295*1fa6dee9SAndroid Build Coastguard Worker		}
296*1fa6dee9SAndroid Build Coastguard Worker		outCtx := &outgoingTransitionContextImpl{tc}
297*1fa6dee9SAndroid Build Coastguard Worker		outgoingVariation := t.mutator.OutgoingTransition(outCtx, sourceVariation)
298*1fa6dee9SAndroid Build Coastguard Worker		for _, err := range outCtx.errs {
299*1fa6dee9SAndroid Build Coastguard Worker			mctx.error(err)
300*1fa6dee9SAndroid Build Coastguard Worker		}
301*1fa6dee9SAndroid Build Coastguard Worker		if mctx.Failed() {
302*1fa6dee9SAndroid Build Coastguard Worker			return outgoingVariation
303*1fa6dee9SAndroid Build Coastguard Worker		}
304*1fa6dee9SAndroid Build Coastguard Worker		inCtx := &incomingTransitionContextImpl{tc}
305*1fa6dee9SAndroid Build Coastguard Worker		finalVariation := t.mutator.IncomingTransition(inCtx, outgoingVariation)
306*1fa6dee9SAndroid Build Coastguard Worker		for _, err := range inCtx.errs {
307*1fa6dee9SAndroid Build Coastguard Worker			mctx.error(err)
308*1fa6dee9SAndroid Build Coastguard Worker		}
309*1fa6dee9SAndroid Build Coastguard Worker		return finalVariation
310*1fa6dee9SAndroid Build Coastguard Worker	}
311*1fa6dee9SAndroid Build Coastguard Worker}
312*1fa6dee9SAndroid Build Coastguard Worker
313*1fa6dee9SAndroid Build Coastguard Workerfunc (t *transitionMutatorImpl) bottomUpMutator(mctx BottomUpMutatorContext) {
314*1fa6dee9SAndroid Build Coastguard Worker	mc := mctx.(*mutatorContext)
315*1fa6dee9SAndroid Build Coastguard Worker	// Fetch and clean up transition mutator state. No locking needed since the
316*1fa6dee9SAndroid Build Coastguard Worker	// only time interaction between multiple modules is required is during the
317*1fa6dee9SAndroid Build Coastguard Worker	// computation of the variations required by a given module.
318*1fa6dee9SAndroid Build Coastguard Worker	variations := mc.module.transitionVariations
319*1fa6dee9SAndroid Build Coastguard Worker	outgoingTransitionCache := mc.module.outgoingTransitionCache
320*1fa6dee9SAndroid Build Coastguard Worker	mc.module.transitionVariations = nil
321*1fa6dee9SAndroid Build Coastguard Worker	mc.module.outgoingTransitionCache = nil
322*1fa6dee9SAndroid Build Coastguard Worker	mc.module.currentTransitionMutator = ""
323*1fa6dee9SAndroid Build Coastguard Worker
324*1fa6dee9SAndroid Build Coastguard Worker	if len(variations) < 1 {
325*1fa6dee9SAndroid Build Coastguard Worker		panic(fmt.Errorf("no variations found for module %s by mutator %s",
326*1fa6dee9SAndroid Build Coastguard Worker			mctx.ModuleName(), t.name))
327*1fa6dee9SAndroid Build Coastguard Worker	}
328*1fa6dee9SAndroid Build Coastguard Worker
329*1fa6dee9SAndroid Build Coastguard Worker	if len(variations) == 1 && variations[0] == "" {
330*1fa6dee9SAndroid Build Coastguard Worker		// Module is not split, just apply the transition
331*1fa6dee9SAndroid Build Coastguard Worker		mc.context.convertDepsToVariation(mc.module, 0,
332*1fa6dee9SAndroid Build Coastguard Worker			chooseDepByIndexes(mc.mutator.name, outgoingTransitionCache))
333*1fa6dee9SAndroid Build Coastguard Worker	} else {
334*1fa6dee9SAndroid Build Coastguard Worker		mc.createVariationsWithTransition(variations, outgoingTransitionCache)
335*1fa6dee9SAndroid Build Coastguard Worker	}
336*1fa6dee9SAndroid Build Coastguard Worker}
337*1fa6dee9SAndroid Build Coastguard Worker
338*1fa6dee9SAndroid Build Coastguard Workerfunc (t *transitionMutatorImpl) mutateMutator(mctx BottomUpMutatorContext) {
339*1fa6dee9SAndroid Build Coastguard Worker	module := mctx.(*mutatorContext).module
340*1fa6dee9SAndroid Build Coastguard Worker	currentVariation := module.variant.variations.get(t.name)
341*1fa6dee9SAndroid Build Coastguard Worker	t.mutator.Mutate(mctx, currentVariation)
342*1fa6dee9SAndroid Build Coastguard Worker}
343*1fa6dee9SAndroid Build Coastguard Worker
344*1fa6dee9SAndroid Build Coastguard Workertype TransitionMutatorHandle interface {
345*1fa6dee9SAndroid Build Coastguard Worker	// NeverFar causes the variations created by this mutator to never be ignored when adding
346*1fa6dee9SAndroid Build Coastguard Worker	// far variation dependencies. Normally, far variation dependencies ignore all the variants
347*1fa6dee9SAndroid Build Coastguard Worker	// of the source module, and only use the variants explicitly requested by the
348*1fa6dee9SAndroid Build Coastguard Worker	// AddFarVariationDependencies call.
349*1fa6dee9SAndroid Build Coastguard Worker	NeverFar() TransitionMutatorHandle
350*1fa6dee9SAndroid Build Coastguard Worker}
351*1fa6dee9SAndroid Build Coastguard Worker
352*1fa6dee9SAndroid Build Coastguard Workertype transitionMutatorHandle struct {
353*1fa6dee9SAndroid Build Coastguard Worker	inner MutatorHandle
354*1fa6dee9SAndroid Build Coastguard Worker}
355*1fa6dee9SAndroid Build Coastguard Worker
356*1fa6dee9SAndroid Build Coastguard Workervar _ TransitionMutatorHandle = (*transitionMutatorHandle)(nil)
357*1fa6dee9SAndroid Build Coastguard Worker
358*1fa6dee9SAndroid Build Coastguard Workerfunc (h *transitionMutatorHandle) NeverFar() TransitionMutatorHandle {
359*1fa6dee9SAndroid Build Coastguard Worker	h.inner.setNeverFar()
360*1fa6dee9SAndroid Build Coastguard Worker	return h
361*1fa6dee9SAndroid Build Coastguard Worker}
362*1fa6dee9SAndroid Build Coastguard Worker
363*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) RegisterTransitionMutator(name string, mutator TransitionMutator) TransitionMutatorHandle {
364*1fa6dee9SAndroid Build Coastguard Worker	impl := &transitionMutatorImpl{name: name, mutator: mutator}
365*1fa6dee9SAndroid Build Coastguard Worker
366*1fa6dee9SAndroid Build Coastguard Worker	c.RegisterTopDownMutator(name+"_propagate", impl.topDownMutator)
367*1fa6dee9SAndroid Build Coastguard Worker	bottomUpHandle := c.RegisterBottomUpMutator(name, impl.bottomUpMutator).setTransitionMutator(impl)
368*1fa6dee9SAndroid Build Coastguard Worker	c.RegisterBottomUpMutator(name+"_mutate", impl.mutateMutator)
369*1fa6dee9SAndroid Build Coastguard Worker	return &transitionMutatorHandle{inner: bottomUpHandle}
370*1fa6dee9SAndroid Build Coastguard Worker}
371*1fa6dee9SAndroid Build Coastguard Worker
372*1fa6dee9SAndroid Build Coastguard Worker// This function is called for every dependency edge to determine which
373*1fa6dee9SAndroid Build Coastguard Worker// variation of the dependency is needed. Its inputs are the depending module,
374*1fa6dee9SAndroid Build Coastguard Worker// its variation, the dependency and the dependency tag.
375*1fa6dee9SAndroid Build Coastguard Workertype Transition func(source *moduleInfo, sourceVariation string, dep *moduleInfo, depTag DependencyTag) string
376