Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/build/build/soong/android/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 20 kB image not shown  

Quelle  transition.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// 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"

//go:generate go run ../../blueprint/gobtools/codegen

// 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[T blueprint.TransitionInfo] 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) []T

 // SplitOnDemand returns the set of additional supported variations.
 // Unlike Split(), these are not created when the transition runs.
 // However if a subsequent mutator requests one of these variations via
 // AddDependency*, the variation will be created adhoc.
 SplitOnDemand(ctx BaseModuleContext) []T

 // 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, sourceTransitionInfo T) T

 // 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, incomingTransitionInfo T) T

 // 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, transitionInfo T)

 // TransitionInfoFromVariation is called when adding dependencies with an explicit variation after the
 // TransitionMutator has already run.  It takes a variation name and returns a TransitionInfo for that
 // variation.  It may not be possible for some TransitionMutators to generate an appropriate TransitionInfo
 // if the variation does not contain all the information from the TransitionInfo, in which case the
 // TransitionMutator can panic in TransitionInfoFromVariation, and adding dependencies with explicit variations
 // for this TransitionMutator is not supported.
 TransitionInfoFromVariation(variation string) T
}

// androidTransitionMutator is a copy of blueprint.TransitionMutator with the context argument types changed
// from blueprint.BaseModuleContext to BaseModuleContext, etc.
type androidTransitionMutator interface {
 Split(ctx BaseModuleContext) []blueprint.TransitionInfo
 SplitOnDemand(ctx BaseModuleContext) []blueprint.TransitionInfo
 OutgoingTransition(ctx OutgoingTransitionContext, sourceTransitionInfo blueprint.TransitionInfo) blueprint.TransitionInfo
 IncomingTransition(ctx IncomingTransitionContext, incomingTransitionInfo blueprint.TransitionInfo) blueprint.TransitionInfo
 Mutate(ctx BottomUpMutatorContext, transitionInfo blueprint.TransitionInfo)
 TransitionInfoFromVariation(variation string) blueprint.TransitionInfo
}

// VariationTransitionMutator is a simpler version of androidTransitionMutator that passes variation strings instead
// of a blueprint.TransitionInfo object.
type VariationTransitionMutator interface {
 Split(ctx BaseModuleContext) []string
 SplitOnDemand(ctx BaseModuleContext) []string
 OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string
 IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string
 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

 // ModuleName returns the name of the module.  This is generally the value that was returned by Module.Name() when
 // the module was created, but may have been modified by calls to BottomUpMutatorContext.Rename.
 ModuleName() string

 // 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

 // 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

 // HasMutatorFinished returns true if the given mutator has finished running.
 // It will panic if given an invalid mutator name.
 HasMutatorFinished(mutatorName string) bool

 // OtherModulePropertyErrorf reports an error at the line number of a property in the given module definition.
 OtherModulePropertyErrorf(module ModuleOrProxy, property string, fmt string, args ...interface{})
}

type OutgoingTransitionContext interface {
 ArchModuleContext
 ModuleProviderContext

 // Module returns the target of the dependency edge for which the transition
 // is being computed
 Module() Module

 // ModuleName returns the name of the module.  This is generally the value that was returned by Module.Name() when
 // the module was created, but may have been modified by calls to BottomUpMutatorContext.Rename.
 ModuleName() string

 // 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
}

// androidTransitionMutatorAdapter wraps an androidTransitionMutator to convert it to a blueprint.TransitionInfo
// by converting the blueprint.*Context objects into android.*Context objects.
type androidTransitionMutatorAdapter struct {
 finalPhase bool
 mutator    androidTransitionMutator
 name       string
}

func (a *androidTransitionMutatorAdapter) Split(ctx blueprint.BaseModuleContext) []blueprint.TransitionInfo {
 if a.finalPhase {
  panic("TransitionMutator not allowed in FinalDepsMutators")
 }
 m := ctx.Module().(Module)
 moduleContext := baseModuleContextPool.Get()
 defer baseModuleContextPool.Put(moduleContext)
 *moduleContext = m.base().baseModuleContextFactory(ctx)
 return a.mutator.Split(moduleContext)
}

func (a *androidTransitionMutatorAdapter) SplitOnDemand(ctx blueprint.BaseModuleContext) []blueprint.TransitionInfo {
 m := ctx.Module().(Module)
 moduleContext := baseModuleContextPool.Get()
 defer baseModuleContextPool.Put(moduleContext)
 *moduleContext = m.base().baseModuleContextFactory(ctx)
 return a.mutator.SplitOnDemand(moduleContext)
}

func (a *androidTransitionMutatorAdapter) OutgoingTransition(bpctx blueprint.OutgoingTransitionContext,
 sourceTransitionInfo blueprint.TransitionInfo) blueprint.TransitionInfo {
 m := bpctx.Module().(Module)
 ctx := outgoingTransitionContextPool.Get()
 defer outgoingTransitionContextPool.Put(ctx)
 *ctx = outgoingTransitionContextImpl{
  archModuleContext: m.base().archModuleContextFactory(bpctx),
  bp:                bpctx,
 }
 return a.mutator.OutgoingTransition(ctx, sourceTransitionInfo)
}

func (a *androidTransitionMutatorAdapter) IncomingTransition(bpctx blueprint.IncomingTransitionContext,
 incomingTransitionInfo blueprint.TransitionInfo) blueprint.TransitionInfo {
 m := bpctx.Module().(Module)
 ctx := incomingTransitionContextPool.Get()
 defer incomingTransitionContextPool.Put(ctx)
 *ctx = incomingTransitionContextImpl{
  archModuleContext: m.base().archModuleContextFactory(bpctx),
  bp:                bpctx,
 }
 return a.mutator.IncomingTransition(ctx, incomingTransitionInfo)
}

func (a *androidTransitionMutatorAdapter) Mutate(ctx blueprint.BottomUpMutatorContext, transitionInfo blueprint.TransitionInfo) {
 am := ctx.Module().(Module)
 var variation string
 if transitionInfo == nil {
  variation = ""
 } else {
  variation = transitionInfo.Variation()
 }
 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)
 }
 if config := ctx.Config().(Config); config.captureBuild && ctx.CaptureModuleForTests() {
  config.modulesForTests.Insert(ctx.ModuleName(), am)
 }

 mctx := bottomUpMutatorContextFactory(ctx, am, a.finalPhase)
 defer bottomUpMutatorContextPool.Put(mctx)
 a.mutator.Mutate(mctx, transitionInfo)
}

func (a *androidTransitionMutatorAdapter) TransitionInfoFromVariation(variation string) blueprint.TransitionInfo {
 return a.mutator.TransitionInfoFromVariation(variation)
}

// variationTransitionMutatorAdapter wraps a VariationTransitionMutator to convert it to an androidTransitionMutator
// by wrapping the string info object used by VariationTransitionMutator with variationTransitionInfo to convert it into
// blueprint.TransitionInfo.
type variationTransitionMutatorAdapter struct {
 m VariationTransitionMutator
}

func (v variationTransitionMutatorAdapter) Split(ctx BaseModuleContext) []blueprint.TransitionInfo {
 variations := v.m.Split(ctx)
 transitionInfos := make([]blueprint.TransitionInfo, 0, len(variations))
 for _, variation := range variations {
  transitionInfos = append(transitionInfos, variationTransitionInfo{variation})
 }
 if ctx.Module().SplitAllVariants() {
  transitionInfos = append(transitionInfos, v.SplitOnDemand(ctx)...)
 }
 return FirstUnique(transitionInfos)
}

func (v variationTransitionMutatorAdapter) SplitOnDemand(ctx BaseModuleContext) []blueprint.TransitionInfo {
 variations := v.m.SplitOnDemand(ctx)
 transitionInfos := make([]blueprint.TransitionInfo, 0, len(variations))
 for _, variation := range variations {
  transitionInfos = append(transitionInfos, variationTransitionInfo{variation})
 }
 return transitionInfos
}

func (v variationTransitionMutatorAdapter) OutgoingTransition(ctx OutgoingTransitionContext,
 sourceTransitionInfo blueprint.TransitionInfo) blueprint.TransitionInfo {

 sourceVariationTransitionInfo, _ := sourceTransitionInfo.(variationTransitionInfo)
 outgoingVariation := v.m.OutgoingTransition(ctx, sourceVariationTransitionInfo.variation)
 return variationTransitionInfo{outgoingVariation}
}

func (v variationTransitionMutatorAdapter) IncomingTransition(ctx IncomingTransitionContext,
 incomingTransitionInfo blueprint.TransitionInfo) blueprint.TransitionInfo {

 incomingVariationTransitionInfo, _ := incomingTransitionInfo.(variationTransitionInfo)
 variation := v.m.IncomingTransition(ctx, incomingVariationTransitionInfo.variation)
 return variationTransitionInfo{variation}
}

func (v variationTransitionMutatorAdapter) Mutate(ctx BottomUpMutatorContext, transitionInfo blueprint.TransitionInfo) {
 variationTransitionInfo, _ := transitionInfo.(variationTransitionInfo)
 v.m.Mutate(ctx, variationTransitionInfo.variation)
}

func (v variationTransitionMutatorAdapter) TransitionInfoFromVariation(variation string) blueprint.TransitionInfo {
 return variationTransitionInfo{variation}
}

// variationTransitionInfo is a blueprint.TransitionInfo that contains a single variation string.
// @auto-generate: gob
type variationTransitionInfo struct {
 variation string
}

func (v variationTransitionInfo) Variation() string {
 return v.variation
}

// genericTransitionMutatorAdapter wraps a TransitionMutator to convert it to an androidTransitionMutator
type genericTransitionMutatorAdapter[T blueprint.TransitionInfo] struct {
 m TransitionMutator[T]
}

// NewGenericTransitionMutatorAdapter is used to convert a generic TransitionMutator[T] into an androidTransitionMutator
// that can be passed to RegisterMutatorsContext.InfoBasedTransition.
func NewGenericTransitionMutatorAdapter[T blueprint.TransitionInfo](m TransitionMutator[T]) androidTransitionMutator {
 return &genericTransitionMutatorAdapter[T]{m}
}

func (g *genericTransitionMutatorAdapter[T]) convertTransitionInfoToT(transitionInfo blueprint.TransitionInfo) T {
 if transitionInfo == nil {
  var zero T
  return zero
 }
 return transitionInfo.(T)
}

func (g *genericTransitionMutatorAdapter[T]) Split(ctx BaseModuleContext) []blueprint.TransitionInfo {
 transitionInfos := g.m.Split(ctx)
 bpTransitionInfos := make([]blueprint.TransitionInfo, 0, len(transitionInfos))
 for _, transitionInfo := range transitionInfos {
  bpTransitionInfos = append(bpTransitionInfos, transitionInfo)
 }
 if ctx.Module().SplitAllVariants() {
  bpTransitionInfos = append(bpTransitionInfos, g.SplitOnDemand(ctx)...)
 }
 return FirstUnique(bpTransitionInfos)
}

func (g *genericTransitionMutatorAdapter[T]) SplitOnDemand(ctx BaseModuleContext) []blueprint.TransitionInfo {
 transitionInfos := g.m.SplitOnDemand(ctx)
 bpTransitionInfos := make([]blueprint.TransitionInfo, 0, len(transitionInfos))
 for _, transitionInfo := range transitionInfos {
  bpTransitionInfos = append(bpTransitionInfos, transitionInfo)
 }
 return bpTransitionInfos
}

func (g *genericTransitionMutatorAdapter[T]) OutgoingTransition(ctx OutgoingTransitionContext, sourceTransitionInfo blueprint.TransitionInfo) blueprint.TransitionInfo {
 sourceTransitionInfoT := g.convertTransitionInfoToT(sourceTransitionInfo)
 return g.m.OutgoingTransition(ctx, sourceTransitionInfoT)
}

func (g *genericTransitionMutatorAdapter[T]) IncomingTransition(ctx IncomingTransitionContext, incomingTransitionInfo blueprint.TransitionInfo) blueprint.TransitionInfo {
 incomingTransitionInfoT := g.convertTransitionInfoToT(incomingTransitionInfo)
 return g.m.IncomingTransition(ctx, incomingTransitionInfoT)
}

func (g *genericTransitionMutatorAdapter[T]) Mutate(ctx BottomUpMutatorContext, transitionInfo blueprint.TransitionInfo) {
 transitionInfoT := g.convertTransitionInfoToT(transitionInfo)
 g.m.Mutate(ctx, transitionInfoT)
}

func (g *genericTransitionMutatorAdapter[T]) TransitionInfoFromVariation(variation string) blueprint.TransitionInfo {
 return g.m.TransitionInfoFromVariation(variation)
}

// incomingTransitionContextImpl wraps a blueprint.IncomingTransitionContext to convert it to an
// IncomingTransitionContext.
type incomingTransitionContextImpl struct {
 archModuleContext
 bp blueprint.IncomingTransitionContext
}

func (c *incomingTransitionContextImpl) Module() Module {
 return c.bp.Module().(Module)
}

func (c *incomingTransitionContextImpl) ModuleName() string {
 return c.bp.ModuleName()
}

func (c *incomingTransitionContextImpl) DepTag() blueprint.DependencyTag {
 return c.bp.DepTag()
}

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 (c *incomingTransitionContextImpl) HasMutatorFinished(mutatorName string) bool {
 return c.bp.HasMutatorFinished(mutatorName)
}

func (c *incomingTransitionContextImpl) OtherModulePropertyErrorf(module ModuleOrProxy, property string, fmt string, args ...interface{}) {
 c.bp.OtherModulePropertyErrorf(module, property, fmt, args...)
}

// outgoingTransitionContextImpl wraps a blueprint.OutgoingTransitionContext to convert it to an
// OutgoingTransitionContext.
type outgoingTransitionContextImpl struct {
 archModuleContext
 bp blueprint.OutgoingTransitionContext
}

func (c *outgoingTransitionContextImpl) Module() Module {
 return c.bp.Module().(Module)
}

func (c *outgoingTransitionContextImpl) ModuleName() string {
 return c.bp.ModuleName()
}

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)
}

// UsesUnbundledVariantDepTag is an interface that dependency tags can implement to indicate they
// want the variant of the module that would be used for unbundled builds. This is used by
// unbundled_builder. Historically, make did not know/care about individual variants, so when
// you listed apps in TARGET_BUILD_APPS, make would build whatever variant was available.
type UsesUnbundledVariantDepTag interface {
 UsesUnbundledVariant()
}

[Dauer der Verarbeitung: 0.18 Sekunden, vorverarbeitet 2026-06-28]