Convert arch and os mutators to TransitionMutators
Replace archMutator and osMutator with TransitionMutators.
Bug: 319288033
Flag: EXEMPT refactor
Test: all soong tests pass
Test: no change to out/soong/*.ninja
Change-Id: I92a4d7c895dd79f1dd8064d0ca90e7010b563525
diff --git a/android/arch.go b/android/arch.go
index a7868ba..942727a 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -396,20 +396,21 @@
// device_supported and host_supported properties to determine which OsTypes are enabled for this
// module, then searches through the Targets to determine which have enabled Targets for this
// module.
-func osMutator(mctx BottomUpMutatorContext) {
- module := mctx.Module()
- base := module.base()
+type osTransitionMutator struct{}
- // Nothing to do for modules that are not architecture specific (e.g. a genrule).
- if !base.ArchSpecific() {
- return
- }
+type allOsInfo struct {
+ Os map[string]OsType
+ Variations []string
+}
- // Collect a list of OSTypes supported by this module based on the HostOrDevice value
- // passed to InitAndroidArchModule and the device_supported and host_supported properties.
+var allOsProvider = blueprint.NewMutatorProvider[*allOsInfo]("os_propagate")
+
+// moduleOSList collects a list of OSTypes supported by this module based on the HostOrDevice
+// value passed to InitAndroidArchModule and the device_supported and host_supported properties.
+func moduleOSList(ctx ConfigContext, base *ModuleBase) []OsType {
var moduleOSList []OsType
for _, os := range osTypeList {
- for _, t := range mctx.Config().Targets[os] {
+ for _, t := range ctx.Config().Targets[os] {
if base.supportsTarget(t) {
moduleOSList = append(moduleOSList, os)
break
@@ -417,53 +418,91 @@
}
}
- createCommonOSVariant := base.commonProperties.CreateCommonOSVariant
+ if base.commonProperties.CreateCommonOSVariant {
+ // A CommonOS variant was requested so add it to the list of OS variants to
+ // create. It needs to be added to the end because it needs to depend on the
+ // the other variants and inter variant dependencies can only be created from a
+ // later variant in that list to an earlier one. That is because variants are
+ // always processed in the order in which they are created.
+ moduleOSList = append(moduleOSList, CommonOS)
+ }
+
+ return moduleOSList
+}
+
+func (o *osTransitionMutator) Split(ctx BaseModuleContext) []string {
+ module := ctx.Module()
+ base := module.base()
+
+ // Nothing to do for modules that are not architecture specific (e.g. a genrule).
+ if !base.ArchSpecific() {
+ return []string{""}
+ }
+
+ moduleOSList := moduleOSList(ctx, base)
// If there are no supported OSes then disable the module.
- if len(moduleOSList) == 0 && !createCommonOSVariant {
+ if len(moduleOSList) == 0 {
base.Disable()
- return
+ return []string{""}
}
// Convert the list of supported OsTypes to the variation names.
osNames := make([]string, len(moduleOSList))
+ osMapping := make(map[string]OsType, len(moduleOSList))
for i, os := range moduleOSList {
osNames[i] = os.String()
+ osMapping[osNames[i]] = os
}
- if createCommonOSVariant {
- // A CommonOS variant was requested so add it to the list of OS variants to
- // create. It needs to be added to the end because it needs to depend on the
- // the other variants in the list returned by CreateVariations(...) and inter
- // variant dependencies can only be created from a later variant in that list to
- // an earlier one. That is because variants are always processed in the order in
- // which they are returned from CreateVariations(...).
- osNames = append(osNames, CommonOS.Name)
- moduleOSList = append(moduleOSList, CommonOS)
+ SetProvider(ctx, allOsProvider, &allOsInfo{
+ Os: osMapping,
+ Variations: osNames,
+ })
+
+ return osNames
+}
+
+func (o *osTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
+ return sourceVariation
+}
+
+func (o *osTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
+ module := ctx.Module()
+ base := module.base()
+
+ if !base.ArchSpecific() {
+ return ""
}
- // Create the variations, annotate each one with which OS it was created for, and
+ return incomingVariation
+}
+
+func (o *osTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
+ module := ctx.Module()
+ base := module.base()
+
+ if variation == "" {
+ return
+ }
+
+ allOsInfo, ok := ModuleProvider(ctx, allOsProvider)
+ if !ok {
+ panic(fmt.Errorf("missing allOsProvider"))
+ }
+
+ // Annotate this variant with which OS it was created for, and
// squash the appropriate OS-specific properties into the top level properties.
- modules := mctx.CreateVariations(osNames...)
- for i, m := range modules {
- m.base().commonProperties.CompileOS = moduleOSList[i]
- m.base().setOSProperties(mctx)
- }
+ base.commonProperties.CompileOS = allOsInfo.Os[variation]
+ base.setOSProperties(ctx)
- if createCommonOSVariant {
+ if variation == CommonOS.String() {
// A CommonOS variant was requested so add dependencies from it (the last one in
// the list) to the OS type specific variants.
- last := len(modules) - 1
- commonOSVariant := modules[last]
- commonOSVariant.base().commonProperties.CommonOSVariant = true
- for _, module := range modules[0:last] {
- // Ignore modules that are enabled. Note, this will only avoid adding
- // dependencies on OsType variants that are explicitly disabled in their
- // properties. The CommonOS variant will still depend on disabled variants
- // if they are disabled afterwards, e.g. in archMutator if
- if module.Enabled(mctx) {
- mctx.AddInterVariantDependency(commonOsToOsSpecificVariantTag, commonOSVariant, module)
- }
+ osList := allOsInfo.Variations[:len(allOsInfo.Variations)-1]
+ for _, os := range osList {
+ variation := []blueprint.Variation{{"os", os}}
+ ctx.AddVariationDependencies(variation, commonOsToOsSpecificVariantTag, ctx.ModuleName())
}
}
}
@@ -496,7 +535,7 @@
var DarwinUniversalVariantTag = archDepTag{name: "darwin universal binary"}
-// archMutator splits a module into a variant for each Target requested by the module. Target selection
+// archTransitionMutator splits a module into a variant for each Target requested by the module. Target selection
// for a module is in three levels, OsClass, multilib, and then Target.
// OsClass selection is determined by:
// - The HostOrDeviceSupported value passed in to InitAndroidArchModule by the module type factory, which selects
@@ -527,25 +566,32 @@
//
// Modules can be initialized with InitAndroidMultiTargetsArchModule, in which case they will be split by OsClass,
// but will have a common Target that is expected to handle all other selected Targets via ctx.MultiTargets().
-func archMutator(mctx BottomUpMutatorContext) {
- module := mctx.Module()
+type archTransitionMutator struct{}
+
+type allArchInfo struct {
+ Targets map[string]Target
+ MultiTargets []Target
+ Primary string
+ Multilib string
+}
+
+var allArchProvider = blueprint.NewMutatorProvider[*allArchInfo]("arch_propagate")
+
+func (a *archTransitionMutator) Split(ctx BaseModuleContext) []string {
+ module := ctx.Module()
base := module.base()
if !base.ArchSpecific() {
- return
+ return []string{""}
}
os := base.commonProperties.CompileOS
if os == CommonOS {
- // Make sure that the target related properties are initialized for the
- // CommonOS variant.
- addTargetProperties(module, commonTargetMap[os.Name], nil, true)
-
// Do not create arch specific variants for the CommonOS variant.
- return
+ return []string{""}
}
- osTargets := mctx.Config().Targets[os]
+ osTargets := ctx.Config().Targets[os]
image := base.commonProperties.ImageVariation
// Filter NativeBridge targets unless they are explicitly supported.
@@ -572,19 +618,18 @@
prefer32 := os == Windows
// Determine the multilib selection for this module.
- ignorePrefer32OnDevice := mctx.Config().IgnorePrefer32OnDevice()
- multilib, extraMultilib := decodeMultilib(base, os, ignorePrefer32OnDevice)
+ multilib, extraMultilib := decodeMultilib(ctx, base)
// Convert the multilib selection into a list of Targets.
targets, err := decodeMultilibTargets(multilib, osTargets, prefer32)
if err != nil {
- mctx.ModuleErrorf("%s", err.Error())
+ ctx.ModuleErrorf("%s", err.Error())
}
// If there are no supported targets disable the module.
if len(targets) == 0 {
base.Disable()
- return
+ return []string{""}
}
// If the module is using extraMultilib, decode the extraMultilib selection into
@@ -593,7 +638,7 @@
if extraMultilib != "" {
multiTargets, err = decodeMultilibTargets(extraMultilib, osTargets, prefer32)
if err != nil {
- mctx.ModuleErrorf("%s", err.Error())
+ ctx.ModuleErrorf("%s", err.Error())
}
multiTargets = filterHostCross(multiTargets, targets[0].HostCross)
}
@@ -601,7 +646,7 @@
// Recovery is always the primary architecture, filter out any other architectures.
// Common arch is also allowed
if image == RecoveryVariation {
- primaryArch := mctx.Config().DevicePrimaryArchType()
+ primaryArch := ctx.Config().DevicePrimaryArchType()
targets = filterToArch(targets, primaryArch, Common)
multiTargets = filterToArch(multiTargets, primaryArch, Common)
}
@@ -609,37 +654,109 @@
// If there are no supported targets disable the module.
if len(targets) == 0 {
base.Disable()
- return
+ return []string{""}
}
// Convert the targets into a list of arch variation names.
targetNames := make([]string, len(targets))
+ targetMapping := make(map[string]Target, len(targets))
for i, target := range targets {
targetNames[i] = target.ArchVariation()
+ targetMapping[targetNames[i]] = targets[i]
}
- // Create the variations, annotate each one with which Target it was created for, and
- // squash the appropriate arch-specific properties into the top level properties.
- modules := mctx.CreateVariations(targetNames...)
- for i, m := range modules {
- addTargetProperties(m, targets[i], multiTargets, i == 0)
- m.base().setArchProperties(mctx)
+ SetProvider(ctx, allArchProvider, &allArchInfo{
+ Targets: targetMapping,
+ MultiTargets: multiTargets,
+ Primary: targetNames[0],
+ Multilib: multilib,
+ })
+ return targetNames
+}
- // Install support doesn't understand Darwin+Arm64
- if os == Darwin && targets[i].HostCross {
- m.base().commonProperties.SkipInstall = true
+func (a *archTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
+ return sourceVariation
+}
+
+func (a *archTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
+ module := ctx.Module()
+ base := module.base()
+
+ if !base.ArchSpecific() {
+ return ""
+ }
+
+ os := base.commonProperties.CompileOS
+ if os == CommonOS {
+ // Do not create arch specific variants for the CommonOS variant.
+ return ""
+ }
+
+ if incomingVariation == "" {
+ multilib, _ := decodeMultilib(ctx, base)
+ if multilib == "common" {
+ return "common"
}
}
+ return incomingVariation
+}
+
+func (a *archTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
+ module := ctx.Module()
+ base := module.base()
+ os := base.commonProperties.CompileOS
+
+ if os == CommonOS {
+ // Make sure that the target related properties are initialized for the
+ // CommonOS variant.
+ addTargetProperties(module, commonTargetMap[os.Name], nil, true)
+ return
+ }
+
+ if variation == "" {
+ return
+ }
+
+ if !base.ArchSpecific() {
+ panic(fmt.Errorf("found variation %q for non arch specifc module", variation))
+ }
+
+ allArchInfo, ok := ModuleProvider(ctx, allArchProvider)
+ if !ok {
+ return
+ }
+
+ target, ok := allArchInfo.Targets[variation]
+ if !ok {
+ panic(fmt.Errorf("missing Target for %q", variation))
+ }
+ primary := variation == allArchInfo.Primary
+ multiTargets := allArchInfo.MultiTargets
+
+ // Annotate the new variant with which Target it was created for, and
+ // squash the appropriate arch-specific properties into the top level properties.
+ addTargetProperties(ctx.Module(), target, multiTargets, primary)
+ base.setArchProperties(ctx)
+
+ // Install support doesn't understand Darwin+Arm64
+ if os == Darwin && target.HostCross {
+ base.commonProperties.SkipInstall = true
+ }
// Create a dependency for Darwin Universal binaries from the primary to secondary
// architecture. The module itself will be responsible for calling lipo to merge the outputs.
if os == Darwin {
- if multilib == "darwin_universal" && len(modules) == 2 {
- mctx.AddInterVariantDependency(DarwinUniversalVariantTag, modules[1], modules[0])
- } else if multilib == "darwin_universal_common_first" && len(modules) == 3 {
- mctx.AddInterVariantDependency(DarwinUniversalVariantTag, modules[2], modules[1])
+ isUniversalBinary := (allArchInfo.Multilib == "darwin_universal" && len(allArchInfo.Targets) == 2) ||
+ allArchInfo.Multilib == "darwin_universal_common_first" && len(allArchInfo.Targets) == 3
+ isPrimary := variation == ctx.Config().BuildArch.String()
+ hasSecondaryConfigured := len(ctx.Config().Targets[Darwin]) > 1
+ if isUniversalBinary && isPrimary && hasSecondaryConfigured {
+ secondaryArch := ctx.Config().Targets[Darwin][1].Arch.String()
+ variation := []blueprint.Variation{{"arch", secondaryArch}}
+ ctx.AddVariationDependencies(variation, DarwinUniversalVariantTag, ctx.ModuleName())
}
}
+
}
// addTargetProperties annotates a variant with the Target is is being compiled for, the list
@@ -656,7 +773,9 @@
// multilib from the factory's call to InitAndroidArchModule if none was set. For modules that
// called InitAndroidMultiTargetsArchModule it always returns "common" for multilib, and returns
// the actual multilib in extraMultilib.
-func decodeMultilib(base *ModuleBase, os OsType, ignorePrefer32OnDevice bool) (multilib, extraMultilib string) {
+func decodeMultilib(ctx ConfigContext, base *ModuleBase) (multilib, extraMultilib string) {
+ os := base.commonProperties.CompileOS
+ ignorePrefer32OnDevice := ctx.Config().IgnorePrefer32OnDevice()
// First check the "android.compile_multilib" or "host.compile_multilib" properties.
switch os.Class {
case Device:
diff --git a/android/arch_test.go b/android/arch_test.go
index 6134a06..57c9010 100644
--- a/android/arch_test.go
+++ b/android/arch_test.go
@@ -451,7 +451,7 @@
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
- if tt.goOS != runtime.GOOS {
+ if tt.goOS != "" && tt.goOS != runtime.GOOS {
t.Skipf("requries runtime.GOOS %s", tt.goOS)
}
diff --git a/android/module.go b/android/module.go
index 47fdc23..ca480bd 100644
--- a/android/module.go
+++ b/android/module.go
@@ -443,12 +443,6 @@
// Set at module initialization time by calling InitCommonOSAndroidMultiTargetsArchModule
CreateCommonOSVariant bool `blueprint:"mutated"`
- // If set to true then this variant is the CommonOS variant that has dependencies on its
- // OsType specific variants.
- //
- // Set by osMutator.
- CommonOSVariant bool `blueprint:"mutated"`
-
// When set to true, this module is not installed to the full install path (ex: under
// out/target/product/<name>/<partition>). It can be installed only to the packaging
// modules like android_filesystem.
@@ -1221,7 +1215,7 @@
// True if the current variant is a CommonOS variant, false otherwise.
func (m *ModuleBase) IsCommonOSVariant() bool {
- return m.commonProperties.CommonOSVariant
+ return m.commonProperties.CompileOS == CommonOS
}
// supportsTarget returns true if the given Target is supported by the current module.
@@ -2204,6 +2198,10 @@
return proptools.Bool(m.commonProperties.Native_bridge_supported)
}
+type ConfigContext interface {
+ Config() Config
+}
+
type ConfigurableEvaluatorContext interface {
Config() Config
OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{})
diff --git a/android/mutator.go b/android/mutator.go
index 2ef4d7f..18a9777 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -148,9 +148,9 @@
}
func registerArchMutator(ctx RegisterMutatorsContext) {
- ctx.BottomUp("os", osMutator).Parallel()
+ ctx.Transition("os", &osTransitionMutator{})
ctx.Transition("image", &imageTransitionMutator{})
- ctx.BottomUp("arch", archMutator).Parallel()
+ ctx.Transition("arch", &archTransitionMutator{})
}
var preDeps = []RegisterMutatorFunc{