Merge "Convert arch and os mutators to TransitionMutators" into main am: 1531a12d2d

Original change: https://android-review.googlesource.com/c/platform/build/soong/+/3262266

Change-Id: I1707a33f7037ee5c36bf7ce1b2b44ca1cef7a9b2
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Colin Cross
2024-09-17 17:46:56 +00:00
committed by Automerger Merge Worker
4 changed files with 198 additions and 81 deletions

View File

@@ -396,20 +396,21 @@ func (target Target) Variations() []blueprint.Variation {
// device_supported and host_supported properties to determine which OsTypes are enabled for this // 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, then searches through the Targets to determine which have enabled Targets for this
// module. // module.
func osMutator(mctx BottomUpMutatorContext) { type osTransitionMutator struct{}
module := mctx.Module()
base := module.base()
// Nothing to do for modules that are not architecture specific (e.g. a genrule). type allOsInfo struct {
if !base.ArchSpecific() { Os map[string]OsType
return Variations []string
} }
// Collect a list of OSTypes supported by this module based on the HostOrDevice value var allOsProvider = blueprint.NewMutatorProvider[*allOsInfo]("os_propagate")
// passed to InitAndroidArchModule and the device_supported and host_supported properties.
// 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 var moduleOSList []OsType
for _, os := range osTypeList { for _, os := range osTypeList {
for _, t := range mctx.Config().Targets[os] { for _, t := range ctx.Config().Targets[os] {
if base.supportsTarget(t) { if base.supportsTarget(t) {
moduleOSList = append(moduleOSList, os) moduleOSList = append(moduleOSList, os)
break break
@@ -417,53 +418,91 @@ func osMutator(mctx BottomUpMutatorContext) {
} }
} }
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 there are no supported OSes then disable the module.
if len(moduleOSList) == 0 && !createCommonOSVariant { if len(moduleOSList) == 0 {
base.Disable() base.Disable()
return return []string{""}
} }
// Convert the list of supported OsTypes to the variation names. // Convert the list of supported OsTypes to the variation names.
osNames := make([]string, len(moduleOSList)) osNames := make([]string, len(moduleOSList))
osMapping := make(map[string]OsType, len(moduleOSList))
for i, os := range moduleOSList { for i, os := range moduleOSList {
osNames[i] = os.String() osNames[i] = os.String()
osMapping[osNames[i]] = os
} }
if createCommonOSVariant { SetProvider(ctx, allOsProvider, &allOsInfo{
// A CommonOS variant was requested so add it to the list of OS variants to Os: osMapping,
// create. It needs to be added to the end because it needs to depend on the Variations: osNames,
// 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 return osNames
// which they are returned from CreateVariations(...). }
osNames = append(osNames, CommonOS.Name)
moduleOSList = append(moduleOSList, CommonOS) 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. // squash the appropriate OS-specific properties into the top level properties.
modules := mctx.CreateVariations(osNames...) base.commonProperties.CompileOS = allOsInfo.Os[variation]
for i, m := range modules { base.setOSProperties(ctx)
m.base().commonProperties.CompileOS = moduleOSList[i]
m.base().setOSProperties(mctx)
}
if createCommonOSVariant { if variation == CommonOS.String() {
// A CommonOS variant was requested so add dependencies from it (the last one in // A CommonOS variant was requested so add dependencies from it (the last one in
// the list) to the OS type specific variants. // the list) to the OS type specific variants.
last := len(modules) - 1 osList := allOsInfo.Variations[:len(allOsInfo.Variations)-1]
commonOSVariant := modules[last] for _, os := range osList {
commonOSVariant.base().commonProperties.CommonOSVariant = true variation := []blueprint.Variation{{"os", os}}
for _, module := range modules[0:last] { ctx.AddVariationDependencies(variation, commonOsToOsSpecificVariantTag, ctx.ModuleName())
// 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)
}
} }
} }
} }
@@ -496,7 +535,7 @@ func GetOsSpecificVariantsOfCommonOSVariant(mctx BaseModuleContext) []Module {
var DarwinUniversalVariantTag = archDepTag{name: "darwin universal binary"} 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. // for a module is in three levels, OsClass, multilib, and then Target.
// OsClass selection is determined by: // OsClass selection is determined by:
// - The HostOrDeviceSupported value passed in to InitAndroidArchModule by the module type factory, which selects // - The HostOrDeviceSupported value passed in to InitAndroidArchModule by the module type factory, which selects
@@ -527,25 +566,32 @@ var DarwinUniversalVariantTag = archDepTag{name: "darwin universal binary"}
// //
// Modules can be initialized with InitAndroidMultiTargetsArchModule, in which case they will be split by OsClass, // 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(). // but will have a common Target that is expected to handle all other selected Targets via ctx.MultiTargets().
func archMutator(mctx BottomUpMutatorContext) { type archTransitionMutator struct{}
module := mctx.Module()
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() base := module.base()
if !base.ArchSpecific() { if !base.ArchSpecific() {
return return []string{""}
} }
os := base.commonProperties.CompileOS os := base.commonProperties.CompileOS
if os == CommonOS { 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. // 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 image := base.commonProperties.ImageVariation
// Filter NativeBridge targets unless they are explicitly supported. // Filter NativeBridge targets unless they are explicitly supported.
@@ -572,19 +618,18 @@ func archMutator(mctx BottomUpMutatorContext) {
prefer32 := os == Windows prefer32 := os == Windows
// Determine the multilib selection for this module. // Determine the multilib selection for this module.
ignorePrefer32OnDevice := mctx.Config().IgnorePrefer32OnDevice() multilib, extraMultilib := decodeMultilib(ctx, base)
multilib, extraMultilib := decodeMultilib(base, os, ignorePrefer32OnDevice)
// Convert the multilib selection into a list of Targets. // Convert the multilib selection into a list of Targets.
targets, err := decodeMultilibTargets(multilib, osTargets, prefer32) targets, err := decodeMultilibTargets(multilib, osTargets, prefer32)
if err != nil { if err != nil {
mctx.ModuleErrorf("%s", err.Error()) ctx.ModuleErrorf("%s", err.Error())
} }
// If there are no supported targets disable the module. // If there are no supported targets disable the module.
if len(targets) == 0 { if len(targets) == 0 {
base.Disable() base.Disable()
return return []string{""}
} }
// If the module is using extraMultilib, decode the extraMultilib selection into // If the module is using extraMultilib, decode the extraMultilib selection into
@@ -593,7 +638,7 @@ func archMutator(mctx BottomUpMutatorContext) {
if extraMultilib != "" { if extraMultilib != "" {
multiTargets, err = decodeMultilibTargets(extraMultilib, osTargets, prefer32) multiTargets, err = decodeMultilibTargets(extraMultilib, osTargets, prefer32)
if err != nil { if err != nil {
mctx.ModuleErrorf("%s", err.Error()) ctx.ModuleErrorf("%s", err.Error())
} }
multiTargets = filterHostCross(multiTargets, targets[0].HostCross) multiTargets = filterHostCross(multiTargets, targets[0].HostCross)
} }
@@ -601,7 +646,7 @@ func archMutator(mctx BottomUpMutatorContext) {
// Recovery is always the primary architecture, filter out any other architectures. // Recovery is always the primary architecture, filter out any other architectures.
// Common arch is also allowed // Common arch is also allowed
if image == RecoveryVariation { if image == RecoveryVariation {
primaryArch := mctx.Config().DevicePrimaryArchType() primaryArch := ctx.Config().DevicePrimaryArchType()
targets = filterToArch(targets, primaryArch, Common) targets = filterToArch(targets, primaryArch, Common)
multiTargets = filterToArch(multiTargets, primaryArch, Common) multiTargets = filterToArch(multiTargets, primaryArch, Common)
} }
@@ -609,37 +654,109 @@ func archMutator(mctx BottomUpMutatorContext) {
// If there are no supported targets disable the module. // If there are no supported targets disable the module.
if len(targets) == 0 { if len(targets) == 0 {
base.Disable() base.Disable()
return return []string{""}
} }
// Convert the targets into a list of arch variation names. // Convert the targets into a list of arch variation names.
targetNames := make([]string, len(targets)) targetNames := make([]string, len(targets))
targetMapping := make(map[string]Target, len(targets))
for i, target := range targets { for i, target := range targets {
targetNames[i] = target.ArchVariation() targetNames[i] = target.ArchVariation()
targetMapping[targetNames[i]] = targets[i]
} }
// Create the variations, annotate each one with which Target it was created for, and SetProvider(ctx, allArchProvider, &allArchInfo{
// squash the appropriate arch-specific properties into the top level properties. Targets: targetMapping,
modules := mctx.CreateVariations(targetNames...) MultiTargets: multiTargets,
for i, m := range modules { Primary: targetNames[0],
addTargetProperties(m, targets[i], multiTargets, i == 0) Multilib: multilib,
m.base().setArchProperties(mctx) })
return targetNames
}
// Install support doesn't understand Darwin+Arm64 func (a *archTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
if os == Darwin && targets[i].HostCross { return sourceVariation
m.base().commonProperties.SkipInstall = true }
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 // 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. // architecture. The module itself will be responsible for calling lipo to merge the outputs.
if os == Darwin { if os == Darwin {
if multilib == "darwin_universal" && len(modules) == 2 { isUniversalBinary := (allArchInfo.Multilib == "darwin_universal" && len(allArchInfo.Targets) == 2) ||
mctx.AddInterVariantDependency(DarwinUniversalVariantTag, modules[1], modules[0]) allArchInfo.Multilib == "darwin_universal_common_first" && len(allArchInfo.Targets) == 3
} else if multilib == "darwin_universal_common_first" && len(modules) == 3 { isPrimary := variation == ctx.Config().BuildArch.String()
mctx.AddInterVariantDependency(DarwinUniversalVariantTag, modules[2], modules[1]) 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 // addTargetProperties annotates a variant with the Target is is being compiled for, the list
@@ -656,7 +773,9 @@ func addTargetProperties(m Module, target Target, multiTargets []Target, primary
// multilib from the factory's call to InitAndroidArchModule if none was set. For modules that // 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 // called InitAndroidMultiTargetsArchModule it always returns "common" for multilib, and returns
// the actual multilib in extraMultilib. // 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. // First check the "android.compile_multilib" or "host.compile_multilib" properties.
switch os.Class { switch os.Class {
case Device: case Device:

View File

@@ -451,7 +451,7 @@ func TestArchMutator(t *testing.T) {
for _, tt := range testCases { for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) { 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) t.Skipf("requries runtime.GOOS %s", tt.goOS)
} }

View File

@@ -443,12 +443,6 @@ type commonProperties struct {
// Set at module initialization time by calling InitCommonOSAndroidMultiTargetsArchModule // Set at module initialization time by calling InitCommonOSAndroidMultiTargetsArchModule
CreateCommonOSVariant bool `blueprint:"mutated"` 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 // 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 // out/target/product/<name>/<partition>). It can be installed only to the packaging
// modules like android_filesystem. // modules like android_filesystem.
@@ -1221,7 +1215,7 @@ func (m *ModuleBase) ArchSpecific() bool {
// True if the current variant is a CommonOS variant, false otherwise. // True if the current variant is a CommonOS variant, false otherwise.
func (m *ModuleBase) IsCommonOSVariant() bool { 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. // supportsTarget returns true if the given Target is supported by the current module.
@@ -2212,6 +2206,10 @@ func (m *ModuleBase) IsNativeBridgeSupported() bool {
return proptools.Bool(m.commonProperties.Native_bridge_supported) return proptools.Bool(m.commonProperties.Native_bridge_supported)
} }
type ConfigContext interface {
Config() Config
}
type ConfigurableEvaluatorContext interface { type ConfigurableEvaluatorContext interface {
Config() Config Config() Config
OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{}) OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{})

View File

@@ -148,9 +148,9 @@ var preArch = []RegisterMutatorFunc{
} }
func registerArchMutator(ctx RegisterMutatorsContext) { func registerArchMutator(ctx RegisterMutatorsContext) {
ctx.BottomUp("os", osMutator).Parallel() ctx.Transition("os", &osTransitionMutator{})
ctx.Transition("image", &imageTransitionMutator{}) ctx.Transition("image", &imageTransitionMutator{})
ctx.BottomUp("arch", archMutator).Parallel() ctx.Transition("arch", &archTransitionMutator{})
} }
var preDeps = []RegisterMutatorFunc{ var preDeps = []RegisterMutatorFunc{