1*333d2b36SAndroid Build Coastguard Worker// Copyright 2016 Google Inc. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage android 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Workerimport ( 18*333d2b36SAndroid Build Coastguard Worker "fmt" 19*333d2b36SAndroid Build Coastguard Worker "path" 20*333d2b36SAndroid Build Coastguard Worker "reflect" 21*333d2b36SAndroid Build Coastguard Worker "runtime" 22*333d2b36SAndroid Build Coastguard Worker 23*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint" 24*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint/proptools" 25*333d2b36SAndroid Build Coastguard Worker) 26*333d2b36SAndroid Build Coastguard Worker 27*333d2b36SAndroid Build Coastguard Worker// This file implements hooks that external module types can use to inject logic into existing 28*333d2b36SAndroid Build Coastguard Worker// module types. Each hook takes an interface as a parameter so that new methods can be added 29*333d2b36SAndroid Build Coastguard Worker// to the interface without breaking existing module types. 30*333d2b36SAndroid Build Coastguard Worker 31*333d2b36SAndroid Build Coastguard Worker// Load hooks are run after the module's properties have been filled from the blueprint file, but 32*333d2b36SAndroid Build Coastguard Worker// before the module has been split into architecture variants, and before defaults modules have 33*333d2b36SAndroid Build Coastguard Worker// been applied. 34*333d2b36SAndroid Build Coastguard Workertype LoadHookContext interface { 35*333d2b36SAndroid Build Coastguard Worker EarlyModuleContext 36*333d2b36SAndroid Build Coastguard Worker 37*333d2b36SAndroid Build Coastguard Worker AppendProperties(...interface{}) 38*333d2b36SAndroid Build Coastguard Worker PrependProperties(...interface{}) 39*333d2b36SAndroid Build Coastguard Worker CreateModule(ModuleFactory, ...interface{}) Module 40*333d2b36SAndroid Build Coastguard Worker CreateModuleInDirectory(ModuleFactory, string, ...interface{}) Module 41*333d2b36SAndroid Build Coastguard Worker 42*333d2b36SAndroid Build Coastguard Worker registerScopedModuleType(name string, factory blueprint.ModuleFactory) 43*333d2b36SAndroid Build Coastguard Worker moduleFactories() map[string]blueprint.ModuleFactory 44*333d2b36SAndroid Build Coastguard Worker} 45*333d2b36SAndroid Build Coastguard Worker 46*333d2b36SAndroid Build Coastguard Worker// Add a hook that will be called once the module has been loaded, i.e. its 47*333d2b36SAndroid Build Coastguard Worker// properties have been initialized from the Android.bp file. 48*333d2b36SAndroid Build Coastguard Worker// 49*333d2b36SAndroid Build Coastguard Worker// Consider using SetDefaultableHook to register a hook for any module that implements 50*333d2b36SAndroid Build Coastguard Worker// DefaultableModule as the hook is called after any defaults have been applied to the 51*333d2b36SAndroid Build Coastguard Worker// module which could reduce duplication and make it easier to use. 52*333d2b36SAndroid Build Coastguard Workerfunc AddLoadHook(m blueprint.Module, hook func(LoadHookContext)) { 53*333d2b36SAndroid Build Coastguard Worker blueprint.AddLoadHook(m, func(ctx blueprint.LoadHookContext) { 54*333d2b36SAndroid Build Coastguard Worker actx := &loadHookContext{ 55*333d2b36SAndroid Build Coastguard Worker earlyModuleContext: m.(Module).base().earlyModuleContextFactory(ctx), 56*333d2b36SAndroid Build Coastguard Worker bp: ctx, 57*333d2b36SAndroid Build Coastguard Worker } 58*333d2b36SAndroid Build Coastguard Worker hook(actx) 59*333d2b36SAndroid Build Coastguard Worker }) 60*333d2b36SAndroid Build Coastguard Worker} 61*333d2b36SAndroid Build Coastguard Worker 62*333d2b36SAndroid Build Coastguard Workerfunc AddLoadHookWithPriority(m blueprint.Module, hook func(LoadHookContext), priority int) { 63*333d2b36SAndroid Build Coastguard Worker blueprint.AddLoadHookWithPriority(m, func(ctx blueprint.LoadHookContext) { 64*333d2b36SAndroid Build Coastguard Worker actx := &loadHookContext{ 65*333d2b36SAndroid Build Coastguard Worker earlyModuleContext: m.(Module).base().earlyModuleContextFactory(ctx), 66*333d2b36SAndroid Build Coastguard Worker bp: ctx, 67*333d2b36SAndroid Build Coastguard Worker } 68*333d2b36SAndroid Build Coastguard Worker hook(actx) 69*333d2b36SAndroid Build Coastguard Worker }, priority) 70*333d2b36SAndroid Build Coastguard Worker} 71*333d2b36SAndroid Build Coastguard Worker 72*333d2b36SAndroid Build Coastguard Workertype loadHookContext struct { 73*333d2b36SAndroid Build Coastguard Worker earlyModuleContext 74*333d2b36SAndroid Build Coastguard Worker bp blueprint.LoadHookContext 75*333d2b36SAndroid Build Coastguard Worker module Module 76*333d2b36SAndroid Build Coastguard Worker} 77*333d2b36SAndroid Build Coastguard Worker 78*333d2b36SAndroid Build Coastguard Workerfunc (l *loadHookContext) moduleFactories() map[string]blueprint.ModuleFactory { 79*333d2b36SAndroid Build Coastguard Worker return l.bp.ModuleFactories() 80*333d2b36SAndroid Build Coastguard Worker} 81*333d2b36SAndroid Build Coastguard Worker 82*333d2b36SAndroid Build Coastguard Workerfunc (l *loadHookContext) appendPrependHelper(props []interface{}, 83*333d2b36SAndroid Build Coastguard Worker extendFn func([]interface{}, interface{}, proptools.ExtendPropertyFilterFunc) error) { 84*333d2b36SAndroid Build Coastguard Worker for _, p := range props { 85*333d2b36SAndroid Build Coastguard Worker err := extendFn(l.Module().base().GetProperties(), p, nil) 86*333d2b36SAndroid Build Coastguard Worker if err != nil { 87*333d2b36SAndroid Build Coastguard Worker if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { 88*333d2b36SAndroid Build Coastguard Worker l.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) 89*333d2b36SAndroid Build Coastguard Worker } else { 90*333d2b36SAndroid Build Coastguard Worker panic(err) 91*333d2b36SAndroid Build Coastguard Worker } 92*333d2b36SAndroid Build Coastguard Worker } 93*333d2b36SAndroid Build Coastguard Worker } 94*333d2b36SAndroid Build Coastguard Worker} 95*333d2b36SAndroid Build Coastguard Workerfunc (l *loadHookContext) AppendProperties(props ...interface{}) { 96*333d2b36SAndroid Build Coastguard Worker l.appendPrependHelper(props, proptools.AppendMatchingProperties) 97*333d2b36SAndroid Build Coastguard Worker} 98*333d2b36SAndroid Build Coastguard Worker 99*333d2b36SAndroid Build Coastguard Workerfunc (l *loadHookContext) PrependProperties(props ...interface{}) { 100*333d2b36SAndroid Build Coastguard Worker l.appendPrependHelper(props, proptools.PrependMatchingProperties) 101*333d2b36SAndroid Build Coastguard Worker} 102*333d2b36SAndroid Build Coastguard Worker 103*333d2b36SAndroid Build Coastguard Workerfunc (l *loadHookContext) createModule(factory blueprint.ModuleFactory, name string, props ...interface{}) blueprint.Module { 104*333d2b36SAndroid Build Coastguard Worker return l.bp.CreateModule(factory, name, props...) 105*333d2b36SAndroid Build Coastguard Worker} 106*333d2b36SAndroid Build Coastguard Worker 107*333d2b36SAndroid Build Coastguard Workerfunc (l *loadHookContext) createModuleInDirectory(factory blueprint.ModuleFactory, name, moduleDir string, props ...interface{}) blueprint.Module { 108*333d2b36SAndroid Build Coastguard Worker return l.bp.CreateModuleInDirectory(factory, name, moduleDir, props...) 109*333d2b36SAndroid Build Coastguard Worker} 110*333d2b36SAndroid Build Coastguard Worker 111*333d2b36SAndroid Build Coastguard Workertype specifyDirectory struct { 112*333d2b36SAndroid Build Coastguard Worker specified bool 113*333d2b36SAndroid Build Coastguard Worker directory string 114*333d2b36SAndroid Build Coastguard Worker} 115*333d2b36SAndroid Build Coastguard Worker 116*333d2b36SAndroid Build Coastguard Workerfunc doesNotSpecifyDirectory() specifyDirectory { 117*333d2b36SAndroid Build Coastguard Worker return specifyDirectory{ 118*333d2b36SAndroid Build Coastguard Worker specified: false, 119*333d2b36SAndroid Build Coastguard Worker directory: "", 120*333d2b36SAndroid Build Coastguard Worker } 121*333d2b36SAndroid Build Coastguard Worker} 122*333d2b36SAndroid Build Coastguard Worker 123*333d2b36SAndroid Build Coastguard Workerfunc specifiesDirectory(directory string) specifyDirectory { 124*333d2b36SAndroid Build Coastguard Worker return specifyDirectory{ 125*333d2b36SAndroid Build Coastguard Worker specified: true, 126*333d2b36SAndroid Build Coastguard Worker directory: directory, 127*333d2b36SAndroid Build Coastguard Worker } 128*333d2b36SAndroid Build Coastguard Worker} 129*333d2b36SAndroid Build Coastguard Worker 130*333d2b36SAndroid Build Coastguard Workertype createModuleContext interface { 131*333d2b36SAndroid Build Coastguard Worker Module() Module 132*333d2b36SAndroid Build Coastguard Worker HasMutatorFinished(mutatorName string) bool 133*333d2b36SAndroid Build Coastguard Worker createModule(blueprint.ModuleFactory, string, ...interface{}) blueprint.Module 134*333d2b36SAndroid Build Coastguard Worker createModuleInDirectory(blueprint.ModuleFactory, string, string, ...interface{}) blueprint.Module 135*333d2b36SAndroid Build Coastguard Worker} 136*333d2b36SAndroid Build Coastguard Worker 137*333d2b36SAndroid Build Coastguard Workerfunc createModule(ctx createModuleContext, factory ModuleFactory, ext string, specifyDirectory specifyDirectory, props ...interface{}) Module { 138*333d2b36SAndroid Build Coastguard Worker if ctx.HasMutatorFinished("defaults") { 139*333d2b36SAndroid Build Coastguard Worker // Creating modules late is oftentimes problematic, because they don't have earlier 140*333d2b36SAndroid Build Coastguard Worker // mutators run on them. Prevent making modules after the defaults mutator has run. 141*333d2b36SAndroid Build Coastguard Worker panic("Cannot create a module after the defaults mutator has finished") 142*333d2b36SAndroid Build Coastguard Worker } 143*333d2b36SAndroid Build Coastguard Worker 144*333d2b36SAndroid Build Coastguard Worker inherited := []interface{}{&ctx.Module().base().commonProperties} 145*333d2b36SAndroid Build Coastguard Worker 146*333d2b36SAndroid Build Coastguard Worker var typeName string 147*333d2b36SAndroid Build Coastguard Worker if typeNameLookup, ok := ModuleTypeByFactory()[reflect.ValueOf(factory)]; ok { 148*333d2b36SAndroid Build Coastguard Worker typeName = typeNameLookup 149*333d2b36SAndroid Build Coastguard Worker } else { 150*333d2b36SAndroid Build Coastguard Worker factoryPtr := reflect.ValueOf(factory).Pointer() 151*333d2b36SAndroid Build Coastguard Worker factoryFunc := runtime.FuncForPC(factoryPtr) 152*333d2b36SAndroid Build Coastguard Worker filePath, _ := factoryFunc.FileLine(factoryPtr) 153*333d2b36SAndroid Build Coastguard Worker typeName = fmt.Sprintf("%s_%s", path.Base(filePath), factoryFunc.Name()) 154*333d2b36SAndroid Build Coastguard Worker } 155*333d2b36SAndroid Build Coastguard Worker typeName = typeName + "_" + ext 156*333d2b36SAndroid Build Coastguard Worker 157*333d2b36SAndroid Build Coastguard Worker var module Module 158*333d2b36SAndroid Build Coastguard Worker if specifyDirectory.specified { 159*333d2b36SAndroid Build Coastguard Worker module = ctx.createModuleInDirectory(ModuleFactoryAdaptor(factory), typeName, specifyDirectory.directory, append(inherited, props...)...).(Module) 160*333d2b36SAndroid Build Coastguard Worker } else { 161*333d2b36SAndroid Build Coastguard Worker module = ctx.createModule(ModuleFactoryAdaptor(factory), typeName, append(inherited, props...)...).(Module) 162*333d2b36SAndroid Build Coastguard Worker } 163*333d2b36SAndroid Build Coastguard Worker 164*333d2b36SAndroid Build Coastguard Worker if ctx.Module().base().variableProperties != nil && module.base().variableProperties != nil { 165*333d2b36SAndroid Build Coastguard Worker src := ctx.Module().base().variableProperties 166*333d2b36SAndroid Build Coastguard Worker dst := []interface{}{ 167*333d2b36SAndroid Build Coastguard Worker module.base().variableProperties, 168*333d2b36SAndroid Build Coastguard Worker // Put an empty copy of the src properties into dst so that properties in src that are not in dst 169*333d2b36SAndroid Build Coastguard Worker // don't cause a "failed to find property to extend" error. 170*333d2b36SAndroid Build Coastguard Worker proptools.CloneEmptyProperties(reflect.ValueOf(src)).Interface(), 171*333d2b36SAndroid Build Coastguard Worker } 172*333d2b36SAndroid Build Coastguard Worker err := proptools.AppendMatchingProperties(dst, src, nil) 173*333d2b36SAndroid Build Coastguard Worker if err != nil { 174*333d2b36SAndroid Build Coastguard Worker panic(err) 175*333d2b36SAndroid Build Coastguard Worker } 176*333d2b36SAndroid Build Coastguard Worker } 177*333d2b36SAndroid Build Coastguard Worker 178*333d2b36SAndroid Build Coastguard Worker return module 179*333d2b36SAndroid Build Coastguard Worker} 180*333d2b36SAndroid Build Coastguard Worker 181*333d2b36SAndroid Build Coastguard Workerfunc (l *loadHookContext) CreateModule(factory ModuleFactory, props ...interface{}) Module { 182*333d2b36SAndroid Build Coastguard Worker return createModule(l, factory, "_loadHookModule", doesNotSpecifyDirectory(), props...) 183*333d2b36SAndroid Build Coastguard Worker} 184*333d2b36SAndroid Build Coastguard Worker 185*333d2b36SAndroid Build Coastguard Workerfunc (l *loadHookContext) CreateModuleInDirectory(factory ModuleFactory, directory string, props ...interface{}) Module { 186*333d2b36SAndroid Build Coastguard Worker return createModule(l, factory, "_loadHookModule", specifiesDirectory(directory), props...) 187*333d2b36SAndroid Build Coastguard Worker} 188*333d2b36SAndroid Build Coastguard Worker 189*333d2b36SAndroid Build Coastguard Workerfunc (l *loadHookContext) registerScopedModuleType(name string, factory blueprint.ModuleFactory) { 190*333d2b36SAndroid Build Coastguard Worker l.bp.RegisterScopedModuleType(name, factory) 191*333d2b36SAndroid Build Coastguard Worker} 192*333d2b36SAndroid Build Coastguard Worker 193*333d2b36SAndroid Build Coastguard Workertype InstallHookContext interface { 194*333d2b36SAndroid Build Coastguard Worker ModuleContext 195*333d2b36SAndroid Build Coastguard Worker SrcPath() Path 196*333d2b36SAndroid Build Coastguard Worker Path() InstallPath 197*333d2b36SAndroid Build Coastguard Worker Symlink() bool 198*333d2b36SAndroid Build Coastguard Worker} 199*333d2b36SAndroid Build Coastguard Worker 200*333d2b36SAndroid Build Coastguard Worker// Install hooks are run after a module creates a rule to install a file or symlink. 201*333d2b36SAndroid Build Coastguard Worker// The installed path is available from InstallHookContext.Path(), and 202*333d2b36SAndroid Build Coastguard Worker// InstallHookContext.Symlink() will be true if it was a symlink. 203*333d2b36SAndroid Build Coastguard Workerfunc AddInstallHook(m blueprint.Module, hook func(InstallHookContext)) { 204*333d2b36SAndroid Build Coastguard Worker h := &m.(Module).base().hooks 205*333d2b36SAndroid Build Coastguard Worker h.install = append(h.install, hook) 206*333d2b36SAndroid Build Coastguard Worker} 207*333d2b36SAndroid Build Coastguard Worker 208*333d2b36SAndroid Build Coastguard Workertype installHookContext struct { 209*333d2b36SAndroid Build Coastguard Worker ModuleContext 210*333d2b36SAndroid Build Coastguard Worker srcPath Path 211*333d2b36SAndroid Build Coastguard Worker path InstallPath 212*333d2b36SAndroid Build Coastguard Worker symlink bool 213*333d2b36SAndroid Build Coastguard Worker} 214*333d2b36SAndroid Build Coastguard Worker 215*333d2b36SAndroid Build Coastguard Workervar _ InstallHookContext = &installHookContext{} 216*333d2b36SAndroid Build Coastguard Worker 217*333d2b36SAndroid Build Coastguard Workerfunc (x *installHookContext) SrcPath() Path { 218*333d2b36SAndroid Build Coastguard Worker return x.srcPath 219*333d2b36SAndroid Build Coastguard Worker} 220*333d2b36SAndroid Build Coastguard Worker 221*333d2b36SAndroid Build Coastguard Workerfunc (x *installHookContext) Path() InstallPath { 222*333d2b36SAndroid Build Coastguard Worker return x.path 223*333d2b36SAndroid Build Coastguard Worker} 224*333d2b36SAndroid Build Coastguard Worker 225*333d2b36SAndroid Build Coastguard Workerfunc (x *installHookContext) Symlink() bool { 226*333d2b36SAndroid Build Coastguard Worker return x.symlink 227*333d2b36SAndroid Build Coastguard Worker} 228*333d2b36SAndroid Build Coastguard Worker 229*333d2b36SAndroid Build Coastguard Workerfunc (x *hooks) runInstallHooks(ctx ModuleContext, srcPath Path, path InstallPath, symlink bool) { 230*333d2b36SAndroid Build Coastguard Worker if len(x.install) > 0 { 231*333d2b36SAndroid Build Coastguard Worker mctx := &installHookContext{ 232*333d2b36SAndroid Build Coastguard Worker ModuleContext: ctx, 233*333d2b36SAndroid Build Coastguard Worker srcPath: srcPath, 234*333d2b36SAndroid Build Coastguard Worker path: path, 235*333d2b36SAndroid Build Coastguard Worker symlink: symlink, 236*333d2b36SAndroid Build Coastguard Worker } 237*333d2b36SAndroid Build Coastguard Worker for _, x := range x.install { 238*333d2b36SAndroid Build Coastguard Worker x(mctx) 239*333d2b36SAndroid Build Coastguard Worker if mctx.Failed() { 240*333d2b36SAndroid Build Coastguard Worker return 241*333d2b36SAndroid Build Coastguard Worker } 242*333d2b36SAndroid Build Coastguard Worker } 243*333d2b36SAndroid Build Coastguard Worker } 244*333d2b36SAndroid Build Coastguard Worker} 245*333d2b36SAndroid Build Coastguard Worker 246*333d2b36SAndroid Build Coastguard Workertype hooks struct { 247*333d2b36SAndroid Build Coastguard Worker install []func(InstallHookContext) 248*333d2b36SAndroid Build Coastguard Worker} 249