// Copyright 2015 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 ( "reflect" "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) // Phases: // run Pre-arch mutators // run archMutator // run Pre-deps mutators // run depsMutator // run PostDeps mutators // run FinalDeps mutators (CreateVariations disallowed in this phase) // continue on to GenerateAndroidBuildActions func registerMutatorsToContext(ctx *blueprint.Context, mutators []*mutator) { for _, t := range mutators { var handle blueprint.MutatorHandle if t.bottomUpMutator != nil { handle = ctx.RegisterBottomUpMutator(t.name, t.bottomUpMutator) } else if t.topDownMutator != nil { handle = ctx.RegisterTopDownMutator(t.name, t.topDownMutator) } if t.parallel { handle.Parallel() } } } func registerMutators(ctx *blueprint.Context, preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc) { mctx := ®isterMutatorsContext{} register := func(funcs []RegisterMutatorFunc) { for _, f := range funcs { f(mctx) } } register(preArch) register(preDeps) mctx.BottomUp("deps", depsMutator).Parallel() register(postDeps) mctx.finalPhase = true register(finalDeps) registerMutatorsToContext(ctx, mctx.mutators) } type registerMutatorsContext struct { mutators []*mutator finalPhase bool } type RegisterMutatorsContext interface { TopDown(name string, m TopDownMutator) MutatorHandle BottomUp(name string, m BottomUpMutator) MutatorHandle } type RegisterMutatorFunc func(RegisterMutatorsContext) var preArch = []RegisterMutatorFunc{ RegisterNamespaceMutator, // Check the visibility rules are valid. // // This must run after the package renamer mutators so that any issues found during // validation of the package's default_visibility property are reported using the // correct package name and not the synthetic name. // // This must also be run before defaults mutators as the rules for validation are // different before checking the rules than they are afterwards. e.g. // visibility: ["//visibility:private", "//visibility:public"] // would be invalid if specified in a module definition but is valid if it results // from something like this: // // defaults { // name: "defaults", // // Be inaccessible outside a package by default. // visibility: ["//visibility:private"] // } // // defaultable_module { // name: "defaultable_module", // defaults: ["defaults"], // // Override the default. // visibility: ["//visibility:public"] // } // RegisterVisibilityRuleChecker, // Apply properties from defaults modules to the referencing modules. // // Any mutators that are added before this will not see any modules created by // a DefaultableHook. RegisterDefaultsPreArchMutators, // Add dependencies on any components so that any component references can be // resolved within the deps mutator. // // Must be run after defaults so it can be used to create dependencies on the // component modules that are creating in a DefaultableHook. // // Must be run before RegisterPrebuiltsPreArchMutators, i.e. before prebuilts are // renamed. That is so that if a module creates components using a prebuilt module // type that any dependencies (which must use prebuilt_ prefixes) are resolved to // the prebuilt module and not the source module. RegisterComponentsMutator, // Create an association between prebuilt modules and their corresponding source // modules (if any). // // Must be run after defaults mutators to ensure that any modules created by // a DefaultableHook can be either a prebuilt or a source module with a matching // prebuilt. RegisterPrebuiltsPreArchMutators, // Gather the visibility rules for all modules for us during visibility enforcement. // // This must come after the defaults mutators to ensure that any visibility supplied // in a defaults module has been successfully applied before the rules are gathered. RegisterVisibilityRuleGatherer, } func registerArchMutator(ctx RegisterMutatorsContext) { ctx.BottomUp("os", osMutator).Parallel() ctx.BottomUp("image", imageMutator).Parallel() ctx.BottomUp("arch", archMutator).Parallel() } var preDeps = []RegisterMutatorFunc{ registerArchMutator, } var postDeps = []RegisterMutatorFunc{ registerPathDepsMutator, RegisterPrebuiltsPostDepsMutators, RegisterVisibilityRuleEnforcer, RegisterNeverallowMutator, RegisterOverridePostDepsMutators, } var finalDeps = []RegisterMutatorFunc{} func PreArchMutators(f RegisterMutatorFunc) { preArch = append(preArch, f) } func PreDepsMutators(f RegisterMutatorFunc) { preDeps = append(preDeps, f) } func PostDepsMutators(f RegisterMutatorFunc) { postDeps = append(postDeps, f) } func FinalDepsMutators(f RegisterMutatorFunc) { finalDeps = append(finalDeps, f) } type TopDownMutator func(TopDownMutatorContext) type TopDownMutatorContext interface { BaseModuleContext MutatorName() string Rename(name string) CreateModule(ModuleFactory, ...interface{}) Module } type topDownMutatorContext struct { bp blueprint.TopDownMutatorContext baseModuleContext } type BottomUpMutator func(BottomUpMutatorContext) type BottomUpMutatorContext interface { BaseModuleContext MutatorName() string Rename(name string) AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) AddReverseDependency(module blueprint.Module, tag blueprint.DependencyTag, name string) CreateVariations(...string) []Module CreateLocalVariations(...string) []Module SetDependencyVariation(string) SetDefaultDependencyVariation(*string) AddVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string) AddFarVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string) AddInterVariantDependency(tag blueprint.DependencyTag, from, to blueprint.Module) ReplaceDependencies(string) ReplaceDependenciesIf(string, blueprint.ReplaceDependencyPredicate) AliasVariation(variationName string) CreateAliasVariation(fromVariationName, toVariationName string) } type bottomUpMutatorContext struct { bp blueprint.BottomUpMutatorContext baseModuleContext finalPhase bool } func (x *registerMutatorsContext) BottomUp(name string, m BottomUpMutator) MutatorHandle { finalPhase := x.finalPhase f := func(ctx blueprint.BottomUpMutatorContext) { if a, ok := ctx.Module().(Module); ok { actx := &bottomUpMutatorContext{ bp: ctx, baseModuleContext: a.base().baseModuleContextFactory(ctx), finalPhase: finalPhase, } m(actx) } } mutator := &mutator{name: name, bottomUpMutator: f} x.mutators = append(x.mutators, mutator) return mutator } func (x *registerMutatorsContext) TopDown(name string, m TopDownMutator) MutatorHandle { f := func(ctx blueprint.TopDownMutatorContext) { if a, ok := ctx.Module().(Module); ok { actx := &topDownMutatorContext{ bp: ctx, baseModuleContext: a.base().baseModuleContextFactory(ctx), } m(actx) } } mutator := &mutator{name: name, topDownMutator: f} x.mutators = append(x.mutators, mutator) return mutator } type MutatorHandle interface { Parallel() MutatorHandle } func (mutator *mutator) Parallel() MutatorHandle { mutator.parallel = true return mutator } func RegisterComponentsMutator(ctx RegisterMutatorsContext) { ctx.BottomUp("component-deps", componentDepsMutator).Parallel() } // A special mutator that runs just prior to the deps mutator to allow the dependencies // on component modules to be added so that they can depend directly on a prebuilt // module. func componentDepsMutator(ctx BottomUpMutatorContext) { if m := ctx.Module(); m.Enabled() { m.ComponentDepsMutator(ctx) } } func depsMutator(ctx BottomUpMutatorContext) { if m := ctx.Module(); m.Enabled() { m.DepsMutator(ctx) } } func (t *topDownMutatorContext) AppendProperties(props ...interface{}) { for _, p := range props { err := proptools.AppendMatchingProperties(t.Module().base().customizableProperties, p, nil) if err != nil { if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { t.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) } else { panic(err) } } } } func (t *topDownMutatorContext) PrependProperties(props ...interface{}) { for _, p := range props { err := proptools.PrependMatchingProperties(t.Module().base().customizableProperties, p, nil) if err != nil { if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { t.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) } else { panic(err) } } } } // android.topDownMutatorContext either has to embed blueprint.TopDownMutatorContext, in which case every method that // has an overridden version in android.BaseModuleContext has to be manually forwarded to BaseModuleContext to avoid // ambiguous method errors, or it has to store a blueprint.TopDownMutatorContext non-embedded, in which case every // non-overridden method has to be forwarded. There are fewer non-overridden methods, so use the latter. The following // methods forward to the identical blueprint versions for topDownMutatorContext and bottomUpMutatorContext. func (t *topDownMutatorContext) MutatorName() string { return t.bp.MutatorName() } func (t *topDownMutatorContext) Rename(name string) { t.bp.Rename(name) t.Module().base().commonProperties.DebugName = name } func (t *topDownMutatorContext) CreateModule(factory ModuleFactory, props ...interface{}) Module { inherited := []interface{}{&t.Module().base().commonProperties} module := t.bp.CreateModule(ModuleFactoryAdaptor(factory), append(inherited, props...)...).(Module) if t.Module().base().variableProperties != nil && module.base().variableProperties != nil { src := t.Module().base().variableProperties dst := []interface{}{ module.base().variableProperties, // Put an empty copy of the src properties into dst so that properties in src that are not in dst // don't cause a "failed to find property to extend" error. proptools.CloneEmptyProperties(reflect.ValueOf(src)).Interface(), } err := proptools.AppendMatchingProperties(dst, src, nil) if err != nil { panic(err) } } return module } func (b *bottomUpMutatorContext) MutatorName() string { return b.bp.MutatorName() } func (b *bottomUpMutatorContext) Rename(name string) { b.bp.Rename(name) b.Module().base().commonProperties.DebugName = name } func (b *bottomUpMutatorContext) AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) { b.bp.AddDependency(module, tag, name...) } func (b *bottomUpMutatorContext) AddReverseDependency(module blueprint.Module, tag blueprint.DependencyTag, name string) { b.bp.AddReverseDependency(module, tag, name) } func (b *bottomUpMutatorContext) CreateVariations(variations ...string) []Module { if b.finalPhase { panic("CreateVariations not allowed in FinalDepsMutators") } modules := b.bp.CreateVariations(variations...) aModules := make([]Module, len(modules)) for i := range variations { aModules[i] = modules[i].(Module) base := aModules[i].base() base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, b.MutatorName()) base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variations[i]) } return aModules } func (b *bottomUpMutatorContext) CreateLocalVariations(variations ...string) []Module { if b.finalPhase { panic("CreateLocalVariations not allowed in FinalDepsMutators") } modules := b.bp.CreateLocalVariations(variations...) aModules := make([]Module, len(modules)) for i := range variations { aModules[i] = modules[i].(Module) base := aModules[i].base() base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, b.MutatorName()) base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variations[i]) } return aModules } func (b *bottomUpMutatorContext) SetDependencyVariation(variation string) { b.bp.SetDependencyVariation(variation) } func (b *bottomUpMutatorContext) SetDefaultDependencyVariation(variation *string) { b.bp.SetDefaultDependencyVariation(variation) } func (b *bottomUpMutatorContext) AddVariationDependencies(variations []blueprint.Variation, tag blueprint.DependencyTag, names ...string) { b.bp.AddVariationDependencies(variations, tag, names...) } func (b *bottomUpMutatorContext) AddFarVariationDependencies(variations []blueprint.Variation, tag blueprint.DependencyTag, names ...string) { b.bp.AddFarVariationDependencies(variations, tag, names...) } func (b *bottomUpMutatorContext) AddInterVariantDependency(tag blueprint.DependencyTag, from, to blueprint.Module) { b.bp.AddInterVariantDependency(tag, from, to) } func (b *bottomUpMutatorContext) ReplaceDependencies(name string) { b.bp.ReplaceDependencies(name) } func (b *bottomUpMutatorContext) ReplaceDependenciesIf(name string, predicate blueprint.ReplaceDependencyPredicate) { b.bp.ReplaceDependenciesIf(name, predicate) } func (b *bottomUpMutatorContext) AliasVariation(variationName string) { b.bp.AliasVariation(variationName) } func (b *bottomUpMutatorContext) CreateAliasVariation(fromVariationName, toVariationName string) { b.bp.CreateAliasVariation(fromVariationName, toVariationName) }