1// Copyright 2017 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package android 16 17import ( 18 "github.com/google/blueprint" 19) 20 21// SingletonContext 22type SingletonContext interface { 23 Config() Config 24 DeviceConfig() DeviceConfig 25 26 ModuleName(module blueprint.Module) string 27 ModuleDir(module blueprint.Module) string 28 ModuleSubDir(module blueprint.Module) string 29 ModuleType(module blueprint.Module) string 30 BlueprintFile(module blueprint.Module) string 31 32 // ModuleProvider returns the value, if any, for the provider for a module. If the value for the 33 // provider was not set it returns the zero value of the type of the provider, which means the 34 // return value can always be type-asserted to the type of the provider. The return value should 35 // always be considered read-only. It panics if called before the appropriate mutator or 36 // GenerateBuildActions pass for the provider on the module. 37 ModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{} 38 39 // ModuleHasProvider returns true if the provider for the given module has been set. 40 ModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool 41 42 ModuleErrorf(module blueprint.Module, format string, args ...interface{}) 43 Errorf(format string, args ...interface{}) 44 Failed() bool 45 46 Variable(pctx PackageContext, name, value string) 47 Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule 48 Build(pctx PackageContext, params BuildParams) 49 50 // Phony creates a Make-style phony rule, a rule with no commands that can depend on other 51 // phony rules or real files. Phony can be called on the same name multiple times to add 52 // additional dependencies. 53 Phony(name string, deps ...Path) 54 55 RequireNinjaVersion(major, minor, micro int) 56 57 // SetNinjaBuildDir sets the value of the top-level "builddir" Ninja variable 58 // that controls where Ninja stores its build log files. This value can be 59 // set at most one time for a single build, later calls are ignored. 60 SetNinjaBuildDir(pctx PackageContext, value string) 61 62 // Eval takes a string with embedded ninja variables, and returns a string 63 // with all of the variables recursively expanded. Any variables references 64 // are expanded in the scope of the PackageContext. 65 Eval(pctx PackageContext, ninjaStr string) (string, error) 66 67 VisitAllModulesBlueprint(visit func(blueprint.Module)) 68 VisitAllModules(visit func(Module)) 69 VisitAllModulesIf(pred func(Module) bool, visit func(Module)) 70 71 VisitDirectDeps(module Module, visit func(Module)) 72 VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) 73 74 // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module 75 VisitDepsDepthFirst(module Module, visit func(Module)) 76 // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module 77 VisitDepsDepthFirstIf(module Module, pred func(Module) bool, 78 visit func(Module)) 79 80 VisitAllModuleVariants(module Module, visit func(Module)) 81 82 PrimaryModule(module Module) Module 83 FinalModule(module Module) Module 84 85 AddNinjaFileDeps(deps ...string) 86 87 // GlobWithDeps returns a list of files that match the specified pattern but do not match any 88 // of the patterns in excludes. It also adds efficient dependencies to rerun the primary 89 // builder whenever a file matching the pattern as added or removed, without rerunning if a 90 // file that does not match the pattern is added to a searched directory. 91 GlobWithDeps(pattern string, excludes []string) ([]string, error) 92} 93 94type singletonAdaptor struct { 95 Singleton 96 97 buildParams []BuildParams 98 ruleParams map[blueprint.Rule]blueprint.RuleParams 99} 100 101var _ testBuildProvider = (*singletonAdaptor)(nil) 102 103func (s *singletonAdaptor) GenerateBuildActions(ctx blueprint.SingletonContext) { 104 sctx := &singletonContextAdaptor{SingletonContext: ctx} 105 if sctx.Config().captureBuild { 106 sctx.ruleParams = make(map[blueprint.Rule]blueprint.RuleParams) 107 } 108 109 s.Singleton.GenerateBuildActions(sctx) 110 111 s.buildParams = sctx.buildParams 112 s.ruleParams = sctx.ruleParams 113} 114 115func (s *singletonAdaptor) BuildParamsForTests() []BuildParams { 116 return s.buildParams 117} 118 119func (s *singletonAdaptor) RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams { 120 return s.ruleParams 121} 122 123type Singleton interface { 124 GenerateBuildActions(SingletonContext) 125} 126 127type singletonContextAdaptor struct { 128 blueprint.SingletonContext 129 130 buildParams []BuildParams 131 ruleParams map[blueprint.Rule]blueprint.RuleParams 132} 133 134func (s *singletonContextAdaptor) Config() Config { 135 return s.SingletonContext.Config().(Config) 136} 137 138func (s *singletonContextAdaptor) DeviceConfig() DeviceConfig { 139 return DeviceConfig{s.Config().deviceConfig} 140} 141 142func (s *singletonContextAdaptor) Variable(pctx PackageContext, name, value string) { 143 s.SingletonContext.Variable(pctx.PackageContext, name, value) 144} 145 146func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule { 147 if s.Config().UseRemoteBuild() { 148 if params.Pool == nil { 149 // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict 150 // jobs to the local parallelism value 151 params.Pool = localPool 152 } else if params.Pool == remotePool { 153 // remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's 154 // pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS 155 // parallelism. 156 params.Pool = nil 157 } 158 } 159 rule := s.SingletonContext.Rule(pctx.PackageContext, name, params, argNames...) 160 if s.Config().captureBuild { 161 s.ruleParams[rule] = params 162 } 163 return rule 164} 165 166func (s *singletonContextAdaptor) Build(pctx PackageContext, params BuildParams) { 167 if s.Config().captureBuild { 168 s.buildParams = append(s.buildParams, params) 169 } 170 bparams := convertBuildParams(params) 171 err := validateBuildParams(bparams) 172 if err != nil { 173 s.Errorf("%s: build parameter validation failed: %s", s.Name(), err.Error()) 174 } 175 s.SingletonContext.Build(pctx.PackageContext, bparams) 176 177} 178 179func (s *singletonContextAdaptor) Phony(name string, deps ...Path) { 180 addPhony(s.Config(), name, deps...) 181} 182 183func (s *singletonContextAdaptor) SetNinjaBuildDir(pctx PackageContext, value string) { 184 s.SingletonContext.SetNinjaBuildDir(pctx.PackageContext, value) 185} 186 187func (s *singletonContextAdaptor) Eval(pctx PackageContext, ninjaStr string) (string, error) { 188 return s.SingletonContext.Eval(pctx.PackageContext, ninjaStr) 189} 190 191// visitAdaptor wraps a visit function that takes an android.Module parameter into 192// a function that takes an blueprint.Module parameter and only calls the visit function if the 193// blueprint.Module is an android.Module. 194func visitAdaptor(visit func(Module)) func(blueprint.Module) { 195 return func(module blueprint.Module) { 196 if aModule, ok := module.(Module); ok { 197 visit(aModule) 198 } 199 } 200} 201 202// predAdaptor wraps a pred function that takes an android.Module parameter 203// into a function that takes an blueprint.Module parameter and only calls the visit function if the 204// blueprint.Module is an android.Module, otherwise returns false. 205func predAdaptor(pred func(Module) bool) func(blueprint.Module) bool { 206 return func(module blueprint.Module) bool { 207 if aModule, ok := module.(Module); ok { 208 return pred(aModule) 209 } else { 210 return false 211 } 212 } 213} 214 215func (s *singletonContextAdaptor) VisitAllModulesBlueprint(visit func(blueprint.Module)) { 216 s.SingletonContext.VisitAllModules(visit) 217} 218 219func (s *singletonContextAdaptor) VisitAllModules(visit func(Module)) { 220 s.SingletonContext.VisitAllModules(visitAdaptor(visit)) 221} 222 223func (s *singletonContextAdaptor) VisitAllModulesIf(pred func(Module) bool, visit func(Module)) { 224 s.SingletonContext.VisitAllModulesIf(predAdaptor(pred), visitAdaptor(visit)) 225} 226 227func (s *singletonContextAdaptor) VisitDirectDeps(module Module, visit func(Module)) { 228 s.SingletonContext.VisitDirectDeps(module, visitAdaptor(visit)) 229} 230 231func (s *singletonContextAdaptor) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) { 232 s.SingletonContext.VisitDirectDepsIf(module, predAdaptor(pred), visitAdaptor(visit)) 233} 234 235func (s *singletonContextAdaptor) VisitDepsDepthFirst(module Module, visit func(Module)) { 236 s.SingletonContext.VisitDepsDepthFirst(module, visitAdaptor(visit)) 237} 238 239func (s *singletonContextAdaptor) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) { 240 s.SingletonContext.VisitDepsDepthFirstIf(module, predAdaptor(pred), visitAdaptor(visit)) 241} 242 243func (s *singletonContextAdaptor) VisitAllModuleVariants(module Module, visit func(Module)) { 244 s.SingletonContext.VisitAllModuleVariants(module, visitAdaptor(visit)) 245} 246 247func (s *singletonContextAdaptor) PrimaryModule(module Module) Module { 248 return s.SingletonContext.PrimaryModule(module).(Module) 249} 250 251func (s *singletonContextAdaptor) FinalModule(module Module) Module { 252 return s.SingletonContext.FinalModule(module).(Module) 253} 254