// 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 ( "fmt" "reflect" "github.com/google/blueprint" ) // A sortable component is one whose registration order affects the order in which it is executed // and so affects the behavior of the build system. As a result it is important for the order in // which they are registered during tests to match the order used at runtime and so the test // infrastructure will sort them to match. // // The sortable components are mutators, singletons and pre-singletons. Module types are not // sortable because their order of registration does not affect the runtime behavior. type sortableComponent interface { // componentName returns the name of the component. // // Uniquely identifies the components within the set of components used at runtimr and during // tests. componentName() string // register registers this component in the supplied context. register(ctx *Context) } type sortableComponents []sortableComponent // registerAll registers all components in this slice with the supplied context. func (r sortableComponents) registerAll(ctx *Context) { for _, c := range r { c.register(ctx) } } type moduleType struct { name string factory ModuleFactory } func (t moduleType) register(ctx *Context) { ctx.RegisterModuleType(t.name, ModuleFactoryAdaptor(t.factory)) } var moduleTypes []moduleType var moduleTypesForDocs = map[string]reflect.Value{} type singleton struct { // True if this should be registered as a pre-singleton, false otherwise. pre bool name string factory SingletonFactory } func newSingleton(name string, factory SingletonFactory) singleton { return singleton{false, name, factory} } func newPreSingleton(name string, factory SingletonFactory) singleton { return singleton{true, name, factory} } func (s singleton) componentName() string { return s.name } func (s singleton) register(ctx *Context) { adaptor := SingletonFactoryAdaptor(ctx, s.factory) if s.pre { ctx.RegisterPreSingletonType(s.name, adaptor) } else { ctx.RegisterSingletonType(s.name, adaptor) } } var _ sortableComponent = singleton{} var singletons sortableComponents var preSingletons sortableComponents type mutator struct { name string bottomUpMutator blueprint.BottomUpMutator topDownMutator blueprint.TopDownMutator parallel bool } var _ sortableComponent = &mutator{} type ModuleFactory func() Module // ModuleFactoryAdaptor wraps a ModuleFactory into a blueprint.ModuleFactory by converting a Module // into a blueprint.Module and a list of property structs func ModuleFactoryAdaptor(factory ModuleFactory) blueprint.ModuleFactory { return func() (blueprint.Module, []interface{}) { module := factory() return module, module.GetProperties() } } type SingletonFactory func() Singleton // SingletonFactoryAdaptor wraps a SingletonFactory into a blueprint.SingletonFactory by converting // a Singleton into a blueprint.Singleton func SingletonFactoryAdaptor(ctx *Context, factory SingletonFactory) blueprint.SingletonFactory { return func() blueprint.Singleton { singleton := factory() if makevars, ok := singleton.(SingletonMakeVarsProvider); ok { registerSingletonMakeVarsProvider(ctx.config, makevars) } return &singletonAdaptor{Singleton: singleton} } } func RegisterModuleType(name string, factory ModuleFactory) { moduleTypes = append(moduleTypes, moduleType{name, factory}) RegisterModuleTypeForDocs(name, reflect.ValueOf(factory)) } // RegisterModuleTypeForDocs associates a module type name with a reflect.Value of the factory // function that has documentation for the module type. It is normally called automatically // by RegisterModuleType, but can be called manually after RegisterModuleType in order to // override the factory method used for documentation, for example if the method passed to // RegisterModuleType was a lambda. func RegisterModuleTypeForDocs(name string, factory reflect.Value) { moduleTypesForDocs[name] = factory } func RegisterSingletonType(name string, factory SingletonFactory) { singletons = append(singletons, newSingleton(name, factory)) } func RegisterPreSingletonType(name string, factory SingletonFactory) { preSingletons = append(preSingletons, newPreSingleton(name, factory)) } type Context struct { *blueprint.Context config Config } func NewContext(config Config) *Context { ctx := &Context{blueprint.NewContext(), config} ctx.SetSrcDir(absSrcDir) return ctx } // RegisterForBazelConversion registers an alternate shadow pipeline of // singletons, module types and mutators to register for converting Blueprint // files to semantically equivalent BUILD files. func (ctx *Context) RegisterForBazelConversion() { for _, t := range moduleTypes { t.register(ctx) } // Required for SingletonModule types, even though we are not using them. for _, t := range singletons { t.register(ctx) } bp2buildMutatorList := []RegisterMutatorFunc{} for t, f := range bp2buildMutators { ctx.config.bp2buildModuleTypeConfig[t] = true bp2buildMutatorList = append(bp2buildMutatorList, f) } RegisterMutatorsForBazelConversion(ctx, bp2buildPreArchMutators, bp2buildDepsMutators, bp2buildMutatorList) } // Register the pipeline of singletons, module types, and mutators for // generating build.ninja and other files for Kati, from Android.bp files. func (ctx *Context) Register() { preSingletons.registerAll(ctx) for _, t := range moduleTypes { t.register(ctx) } if ctx.config.BazelContext.BazelEnabled() { // Hydrate the configuration of bp2build-enabled module types. This is // required as a signal to identify which modules should be deferred to // Bazel in mixed builds, if it is enabled. for t, _ := range bp2buildMutators { ctx.config.bp2buildModuleTypeConfig[t] = true } } mutators := collateGloballyRegisteredMutators() mutators.registerAll(ctx) singletons := collateGloballyRegisteredSingletons() singletons.registerAll(ctx) } func collateGloballyRegisteredSingletons() sortableComponents { allSingletons := append(sortableComponents(nil), singletons...) allSingletons = append(allSingletons, singleton{false, "bazeldeps", BazelSingleton}, // Register phony just before makevars so it can write out its phony rules as Make rules singleton{false, "phony", phonySingletonFactory}, // Register makevars after other singletons so they can export values through makevars singleton{false, "makevars", makeVarsSingletonFunc}, // Register env and ninjadeps last so that they can track all used environment variables and // Ninja file dependencies stored in the config. singleton{false, "ninjadeps", ninjaDepsSingletonFactory}, ) return allSingletons } func ModuleTypeFactories() map[string]ModuleFactory { ret := make(map[string]ModuleFactory) for _, t := range moduleTypes { ret[t.name] = t.factory } return ret } func ModuleTypeFactoriesForDocs() map[string]reflect.Value { return moduleTypesForDocs } // Interface for registering build components. // // Provided to allow registration of build components to be shared between the runtime // and test environments. type RegistrationContext interface { RegisterModuleType(name string, factory ModuleFactory) RegisterSingletonModuleType(name string, factory SingletonModuleFactory) RegisterPreSingletonType(name string, factory SingletonFactory) RegisterSingletonType(name string, factory SingletonFactory) PreArchMutators(f RegisterMutatorFunc) // Register pre arch mutators that are hard coded into mutator.go. // // Only registers mutators for testing, is a noop on the InitRegistrationContext. HardCodedPreArchMutators(f RegisterMutatorFunc) PreDepsMutators(f RegisterMutatorFunc) PostDepsMutators(f RegisterMutatorFunc) FinalDepsMutators(f RegisterMutatorFunc) } // Used to register build components from an init() method, e.g. // // init() { // RegisterBuildComponents(android.InitRegistrationContext) // } // // func RegisterBuildComponents(ctx android.RegistrationContext) { // ctx.RegisterModuleType(...) // ... // } // // Extracting the actual registration into a separate RegisterBuildComponents(ctx) function // allows it to be used to initialize test context, e.g. // // ctx := android.NewTestContext(config) // RegisterBuildComponents(ctx) var InitRegistrationContext RegistrationContext = &initRegistrationContext{ moduleTypes: make(map[string]ModuleFactory), singletonTypes: make(map[string]SingletonFactory), preSingletonTypes: make(map[string]SingletonFactory), } // Make sure the TestContext implements RegistrationContext. var _ RegistrationContext = (*TestContext)(nil) type initRegistrationContext struct { moduleTypes map[string]ModuleFactory singletonTypes map[string]SingletonFactory preSingletonTypes map[string]SingletonFactory moduleTypesForDocs map[string]reflect.Value } func (ctx *initRegistrationContext) RegisterModuleType(name string, factory ModuleFactory) { if _, present := ctx.moduleTypes[name]; present { panic(fmt.Sprintf("module type %q is already registered", name)) } ctx.moduleTypes[name] = factory RegisterModuleType(name, factory) RegisterModuleTypeForDocs(name, reflect.ValueOf(factory)) } func (ctx *initRegistrationContext) RegisterSingletonModuleType(name string, factory SingletonModuleFactory) { s, m := SingletonModuleFactoryAdaptor(name, factory) ctx.RegisterSingletonType(name, s) ctx.RegisterModuleType(name, m) // Overwrite moduleTypesForDocs with the original factory instead of the lambda returned by // SingletonModuleFactoryAdaptor so that docs can find the module type documentation on the // factory method. RegisterModuleTypeForDocs(name, reflect.ValueOf(factory)) } func (ctx *initRegistrationContext) RegisterSingletonType(name string, factory SingletonFactory) { if _, present := ctx.singletonTypes[name]; present { panic(fmt.Sprintf("singleton type %q is already registered", name)) } ctx.singletonTypes[name] = factory RegisterSingletonType(name, factory) } func (ctx *initRegistrationContext) RegisterPreSingletonType(name string, factory SingletonFactory) { if _, present := ctx.preSingletonTypes[name]; present { panic(fmt.Sprintf("pre singleton type %q is already registered", name)) } ctx.preSingletonTypes[name] = factory RegisterPreSingletonType(name, factory) } func (ctx *initRegistrationContext) PreArchMutators(f RegisterMutatorFunc) { PreArchMutators(f) } func (ctx *initRegistrationContext) HardCodedPreArchMutators(f RegisterMutatorFunc) { // Nothing to do as the mutators are hard code in preArch in mutator.go } func (ctx *initRegistrationContext) PreDepsMutators(f RegisterMutatorFunc) { PreDepsMutators(f) } func (ctx *initRegistrationContext) PostDepsMutators(f RegisterMutatorFunc) { PostDepsMutators(f) } func (ctx *initRegistrationContext) FinalDepsMutators(f RegisterMutatorFunc) { FinalDepsMutators(f) }