1*333d2b36SAndroid Build Coastguard Worker// Copyright 2020 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 "sync" 20*333d2b36SAndroid Build Coastguard Worker 21*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint" 22*333d2b36SAndroid Build Coastguard Worker) 23*333d2b36SAndroid Build Coastguard Worker 24*333d2b36SAndroid Build Coastguard Worker// A SingletonModule is halfway between a Singleton and a Module. It has access to visiting 25*333d2b36SAndroid Build Coastguard Worker// other modules via its GenerateSingletonBuildActions method, but must be defined in an Android.bp 26*333d2b36SAndroid Build Coastguard Worker// file and can also be depended on like a module. It must be used zero or one times in an 27*333d2b36SAndroid Build Coastguard Worker// Android.bp file, and it can only have a single variant. 28*333d2b36SAndroid Build Coastguard Worker// 29*333d2b36SAndroid Build Coastguard Worker// The SingletonModule's GenerateAndroidBuildActions method will be called before any normal or 30*333d2b36SAndroid Build Coastguard Worker// singleton module that depends on it, but its GenerateSingletonBuildActions method will be called 31*333d2b36SAndroid Build Coastguard Worker// after all modules, in registration order with other singletons and singleton modules. 32*333d2b36SAndroid Build Coastguard Worker// GenerateAndroidBuildActions and GenerateSingletonBuildActions will not be called if the 33*333d2b36SAndroid Build Coastguard Worker// SingletonModule was not instantiated in an Android.bp file. 34*333d2b36SAndroid Build Coastguard Worker// 35*333d2b36SAndroid Build Coastguard Worker// Since the SingletonModule rules likely depend on the modules visited during 36*333d2b36SAndroid Build Coastguard Worker// GenerateSingletonBuildActions, the GenerateAndroidBuildActions is unlikely to produce any 37*333d2b36SAndroid Build Coastguard Worker// rules directly. Instead, it will probably set some providers to paths that will later have rules 38*333d2b36SAndroid Build Coastguard Worker// generated to produce them in GenerateSingletonBuildActions. 39*333d2b36SAndroid Build Coastguard Worker// 40*333d2b36SAndroid Build Coastguard Worker// The expected use case for a SingletonModule is a module that produces files that depend on all 41*333d2b36SAndroid Build Coastguard Worker// modules in the tree and will be used by other modules. For example it could produce a text 42*333d2b36SAndroid Build Coastguard Worker// file that lists all modules that meet a certain criteria, and that text file could be an input 43*333d2b36SAndroid Build Coastguard Worker// to another module. Care must be taken that the ninja rules produced by the SingletonModule 44*333d2b36SAndroid Build Coastguard Worker// don't produce a cycle by referencing output files of rules of modules that depend on the 45*333d2b36SAndroid Build Coastguard Worker// SingletonModule. 46*333d2b36SAndroid Build Coastguard Worker// 47*333d2b36SAndroid Build Coastguard Worker// A SingletonModule must embed a SingletonModuleBase struct, and its factory method must be 48*333d2b36SAndroid Build Coastguard Worker// registered with RegisterSingletonModuleType from an init() function. 49*333d2b36SAndroid Build Coastguard Worker// 50*333d2b36SAndroid Build Coastguard Worker// A SingletonModule can also implement SingletonMakeVarsProvider to export values to Make. 51*333d2b36SAndroid Build Coastguard Workertype SingletonModule interface { 52*333d2b36SAndroid Build Coastguard Worker Module 53*333d2b36SAndroid Build Coastguard Worker GenerateSingletonBuildActions(SingletonContext) 54*333d2b36SAndroid Build Coastguard Worker singletonModuleBase() *SingletonModuleBase 55*333d2b36SAndroid Build Coastguard Worker} 56*333d2b36SAndroid Build Coastguard Worker 57*333d2b36SAndroid Build Coastguard Worker// SingletonModuleBase must be embedded into implementers of the SingletonModule interface. 58*333d2b36SAndroid Build Coastguard Workertype SingletonModuleBase struct { 59*333d2b36SAndroid Build Coastguard Worker ModuleBase 60*333d2b36SAndroid Build Coastguard Worker 61*333d2b36SAndroid Build Coastguard Worker lock sync.Mutex 62*333d2b36SAndroid Build Coastguard Worker bp string 63*333d2b36SAndroid Build Coastguard Worker variant string 64*333d2b36SAndroid Build Coastguard Worker} 65*333d2b36SAndroid Build Coastguard Worker 66*333d2b36SAndroid Build Coastguard Worker// GenerateBuildActions wraps the ModuleBase GenerateBuildActions method, verifying it was only 67*333d2b36SAndroid Build Coastguard Worker// called once to prevent multiple variants of a SingletonModule. 68*333d2b36SAndroid Build Coastguard Workerfunc (smb *SingletonModuleBase) GenerateBuildActions(ctx blueprint.ModuleContext) { 69*333d2b36SAndroid Build Coastguard Worker smb.lock.Lock() 70*333d2b36SAndroid Build Coastguard Worker if smb.variant != "" { 71*333d2b36SAndroid Build Coastguard Worker ctx.ModuleErrorf("GenerateAndroidBuildActions already called for variant %q, SingletonModules can only have one variant", smb.variant) 72*333d2b36SAndroid Build Coastguard Worker } 73*333d2b36SAndroid Build Coastguard Worker smb.variant = ctx.ModuleSubDir() 74*333d2b36SAndroid Build Coastguard Worker smb.lock.Unlock() 75*333d2b36SAndroid Build Coastguard Worker 76*333d2b36SAndroid Build Coastguard Worker smb.ModuleBase.GenerateBuildActions(ctx) 77*333d2b36SAndroid Build Coastguard Worker} 78*333d2b36SAndroid Build Coastguard Worker 79*333d2b36SAndroid Build Coastguard Worker// InitAndroidSingletonModule must be called from the SingletonModule's factory function to 80*333d2b36SAndroid Build Coastguard Worker// initialize SingletonModuleBase. 81*333d2b36SAndroid Build Coastguard Workerfunc InitAndroidSingletonModule(sm SingletonModule) { 82*333d2b36SAndroid Build Coastguard Worker InitAndroidModule(sm) 83*333d2b36SAndroid Build Coastguard Worker} 84*333d2b36SAndroid Build Coastguard Worker 85*333d2b36SAndroid Build Coastguard Worker// singletonModuleBase retrieves the embedded SingletonModuleBase from a SingletonModule. 86*333d2b36SAndroid Build Coastguard Workerfunc (smb *SingletonModuleBase) singletonModuleBase() *SingletonModuleBase { return smb } 87*333d2b36SAndroid Build Coastguard Worker 88*333d2b36SAndroid Build Coastguard Worker// SingletonModuleFactory is a factory method that returns a SingletonModule. 89*333d2b36SAndroid Build Coastguard Workertype SingletonModuleFactory func() SingletonModule 90*333d2b36SAndroid Build Coastguard Worker 91*333d2b36SAndroid Build Coastguard Worker// SingletonModuleFactoryAdaptor converts a SingletonModuleFactory into a SingletonFactory and a 92*333d2b36SAndroid Build Coastguard Worker// ModuleFactory. 93*333d2b36SAndroid Build Coastguard Workerfunc SingletonModuleFactoryAdaptor(name string, factory SingletonModuleFactory) (SingletonFactory, ModuleFactory) { 94*333d2b36SAndroid Build Coastguard Worker // The sm variable acts as a static holder of the only SingletonModule instance. Calls to the 95*333d2b36SAndroid Build Coastguard Worker // returned SingletonFactory and ModuleFactory lambdas will always return the same sm value. 96*333d2b36SAndroid Build Coastguard Worker // The SingletonFactory is only expected to be called once, but the ModuleFactory may be 97*333d2b36SAndroid Build Coastguard Worker // called multiple times if the module is replaced with a clone of itself at the end of 98*333d2b36SAndroid Build Coastguard Worker // blueprint.ResolveDependencies. 99*333d2b36SAndroid Build Coastguard Worker var sm SingletonModule 100*333d2b36SAndroid Build Coastguard Worker s := func() Singleton { 101*333d2b36SAndroid Build Coastguard Worker sm = factory() 102*333d2b36SAndroid Build Coastguard Worker return &singletonModuleSingletonAdaptor{sm} 103*333d2b36SAndroid Build Coastguard Worker } 104*333d2b36SAndroid Build Coastguard Worker m := func() Module { 105*333d2b36SAndroid Build Coastguard Worker if sm == nil { 106*333d2b36SAndroid Build Coastguard Worker panic(fmt.Errorf("Singleton %q for SingletonModule was not instantiated", name)) 107*333d2b36SAndroid Build Coastguard Worker } 108*333d2b36SAndroid Build Coastguard Worker 109*333d2b36SAndroid Build Coastguard Worker // Check for multiple uses of a SingletonModule in a LoadHook. Checking directly in the 110*333d2b36SAndroid Build Coastguard Worker // factory would incorrectly flag when the factory was called again when the module is 111*333d2b36SAndroid Build Coastguard Worker // replaced with a clone of itself at the end of blueprint.ResolveDependencies. 112*333d2b36SAndroid Build Coastguard Worker AddLoadHook(sm, func(ctx LoadHookContext) { 113*333d2b36SAndroid Build Coastguard Worker smb := sm.singletonModuleBase() 114*333d2b36SAndroid Build Coastguard Worker smb.lock.Lock() 115*333d2b36SAndroid Build Coastguard Worker defer smb.lock.Unlock() 116*333d2b36SAndroid Build Coastguard Worker if smb.bp != "" { 117*333d2b36SAndroid Build Coastguard Worker ctx.ModuleErrorf("Duplicate SingletonModule %q, previously used in %s", name, smb.bp) 118*333d2b36SAndroid Build Coastguard Worker } 119*333d2b36SAndroid Build Coastguard Worker smb.bp = ctx.BlueprintsFile() 120*333d2b36SAndroid Build Coastguard Worker }) 121*333d2b36SAndroid Build Coastguard Worker return sm 122*333d2b36SAndroid Build Coastguard Worker } 123*333d2b36SAndroid Build Coastguard Worker return s, m 124*333d2b36SAndroid Build Coastguard Worker} 125*333d2b36SAndroid Build Coastguard Worker 126*333d2b36SAndroid Build Coastguard Worker// singletonModuleSingletonAdaptor makes a SingletonModule into a Singleton by translating the 127*333d2b36SAndroid Build Coastguard Worker// GenerateSingletonBuildActions method to Singleton.GenerateBuildActions. 128*333d2b36SAndroid Build Coastguard Workertype singletonModuleSingletonAdaptor struct { 129*333d2b36SAndroid Build Coastguard Worker sm SingletonModule 130*333d2b36SAndroid Build Coastguard Worker} 131*333d2b36SAndroid Build Coastguard Worker 132*333d2b36SAndroid Build Coastguard Worker// GenerateBuildActions calls the SingletonModule's GenerateSingletonBuildActions method, but only 133*333d2b36SAndroid Build Coastguard Worker// if the module was defined in an Android.bp file. 134*333d2b36SAndroid Build Coastguard Workerfunc (smsa *singletonModuleSingletonAdaptor) GenerateBuildActions(ctx SingletonContext) { 135*333d2b36SAndroid Build Coastguard Worker if smsa.sm.singletonModuleBase().bp != "" { 136*333d2b36SAndroid Build Coastguard Worker smsa.sm.GenerateSingletonBuildActions(ctx) 137*333d2b36SAndroid Build Coastguard Worker } 138*333d2b36SAndroid Build Coastguard Worker} 139*333d2b36SAndroid Build Coastguard Worker 140*333d2b36SAndroid Build Coastguard Workerfunc (smsa *singletonModuleSingletonAdaptor) MakeVars(ctx MakeVarsContext) { 141*333d2b36SAndroid Build Coastguard Worker if smsa.sm.singletonModuleBase().bp != "" { 142*333d2b36SAndroid Build Coastguard Worker if makeVars, ok := smsa.sm.(SingletonMakeVarsProvider); ok { 143*333d2b36SAndroid Build Coastguard Worker makeVars.MakeVars(ctx) 144*333d2b36SAndroid Build Coastguard Worker } 145*333d2b36SAndroid Build Coastguard Worker } 146*333d2b36SAndroid Build Coastguard Worker} 147