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 ModuleErrorf(module blueprint.Module, format string, args ...interface{}) 33 Errorf(format string, args ...interface{}) 34 Failed() bool 35 36 Variable(pctx PackageContext, name, value string) 37 Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule 38 Build(pctx PackageContext, params BuildParams) 39 40 // Phony creates a Make-style phony rule, a rule with no commands that can depend on other 41 // phony rules or real files. Phony can be called on the same name multiple times to add 42 // additional dependencies. 43 Phony(name string, deps ...Path) 44 45 RequireNinjaVersion(major, minor, micro int) 46 47 // SetNinjaBuildDir sets the value of the top-level "builddir" Ninja variable 48 // that controls where Ninja stores its build log files. This value can be 49 // set at most one time for a single build, later calls are ignored. 50 SetNinjaBuildDir(pctx PackageContext, value string) 51 52 // Eval takes a string with embedded ninja variables, and returns a string 53 // with all of the variables recursively expanded. Any variables references 54 // are expanded in the scope of the PackageContext. 55 Eval(pctx PackageContext, ninjaStr string) (string, error) 56 57 VisitAllModulesBlueprint(visit func(blueprint.Module)) 58 VisitAllModules(visit func(Module)) 59 VisitAllModulesIf(pred func(Module) bool, visit func(Module)) 60 61 VisitDirectDeps(module Module, visit func(Module)) 62 VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) 63 64 // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module 65 VisitDepsDepthFirst(module Module, visit func(Module)) 66 // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module 67 VisitDepsDepthFirstIf(module Module, pred func(Module) bool, 68 visit func(Module)) 69 70 VisitAllModuleVariants(module Module, visit func(Module)) 71 72 PrimaryModule(module Module) Module 73 FinalModule(module Module) Module 74 75 AddNinjaFileDeps(deps ...string) 76 77 // GlobWithDeps returns a list of files that match the specified pattern but do not match any 78 // of the patterns in excludes. It also adds efficient dependencies to rerun the primary 79 // builder whenever a file matching the pattern as added or removed, without rerunning if a 80 // file that does not match the pattern is added to a searched directory. 81 GlobWithDeps(pattern string, excludes []string) ([]string, error) 82} 83 84type singletonAdaptor struct { 85 Singleton 86 87 buildParams []BuildParams 88 ruleParams map[blueprint.Rule]blueprint.RuleParams 89} 90 91var _ testBuildProvider = (*singletonAdaptor)(nil) 92 93func (s *singletonAdaptor) GenerateBuildActions(ctx blueprint.SingletonContext) { 94 sctx := &singletonContextAdaptor{SingletonContext: ctx} 95 if sctx.Config().captureBuild { 96 sctx.ruleParams = make(map[blueprint.Rule]blueprint.RuleParams) 97 } 98 99 s.Singleton.GenerateBuildActions(sctx) 100 101 s.buildParams = sctx.buildParams 102 s.ruleParams = sctx.ruleParams 103} 104 105func (s *singletonAdaptor) BuildParamsForTests() []BuildParams { 106 return s.buildParams 107} 108 109func (s *singletonAdaptor) RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams { 110 return s.ruleParams 111} 112 113type Singleton interface { 114 GenerateBuildActions(SingletonContext) 115} 116 117type singletonContextAdaptor struct { 118 blueprint.SingletonContext 119 120 buildParams []BuildParams 121 ruleParams map[blueprint.Rule]blueprint.RuleParams 122} 123 124func (s *singletonContextAdaptor) Config() Config { 125 return s.SingletonContext.Config().(Config) 126} 127 128func (s *singletonContextAdaptor) DeviceConfig() DeviceConfig { 129 return DeviceConfig{s.Config().deviceConfig} 130} 131 132func (s *singletonContextAdaptor) Variable(pctx PackageContext, name, value string) { 133 s.SingletonContext.Variable(pctx.PackageContext, name, value) 134} 135 136func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule { 137 if s.Config().UseRemoteBuild() { 138 if params.Pool == nil { 139 // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict 140 // jobs to the local parallelism value 141 params.Pool = localPool 142 } else if params.Pool == remotePool { 143 // remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's 144 // pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS 145 // parallelism. 146 params.Pool = nil 147 } 148 } 149 rule := s.SingletonContext.Rule(pctx.PackageContext, name, params, argNames...) 150 if s.Config().captureBuild { 151 s.ruleParams[rule] = params 152 } 153 return rule 154} 155 156func (s *singletonContextAdaptor) Build(pctx PackageContext, params BuildParams) { 157 if s.Config().captureBuild { 158 s.buildParams = append(s.buildParams, params) 159 } 160 bparams := convertBuildParams(params) 161 s.SingletonContext.Build(pctx.PackageContext, bparams) 162 163} 164 165func (s *singletonContextAdaptor) Phony(name string, deps ...Path) { 166 addPhony(s.Config(), name, deps...) 167} 168 169func (s *singletonContextAdaptor) SetNinjaBuildDir(pctx PackageContext, value string) { 170 s.SingletonContext.SetNinjaBuildDir(pctx.PackageContext, value) 171} 172 173func (s *singletonContextAdaptor) Eval(pctx PackageContext, ninjaStr string) (string, error) { 174 return s.SingletonContext.Eval(pctx.PackageContext, ninjaStr) 175} 176 177// visitAdaptor wraps a visit function that takes an android.Module parameter into 178// a function that takes an blueprint.Module parameter and only calls the visit function if the 179// blueprint.Module is an android.Module. 180func visitAdaptor(visit func(Module)) func(blueprint.Module) { 181 return func(module blueprint.Module) { 182 if aModule, ok := module.(Module); ok { 183 visit(aModule) 184 } 185 } 186} 187 188// predAdaptor wraps a pred function that takes an android.Module parameter 189// into a function that takes an blueprint.Module parameter and only calls the visit function if the 190// blueprint.Module is an android.Module, otherwise returns false. 191func predAdaptor(pred func(Module) bool) func(blueprint.Module) bool { 192 return func(module blueprint.Module) bool { 193 if aModule, ok := module.(Module); ok { 194 return pred(aModule) 195 } else { 196 return false 197 } 198 } 199} 200 201func (s *singletonContextAdaptor) VisitAllModulesBlueprint(visit func(blueprint.Module)) { 202 s.SingletonContext.VisitAllModules(visit) 203} 204 205func (s *singletonContextAdaptor) VisitAllModules(visit func(Module)) { 206 s.SingletonContext.VisitAllModules(visitAdaptor(visit)) 207} 208 209func (s *singletonContextAdaptor) VisitAllModulesIf(pred func(Module) bool, visit func(Module)) { 210 s.SingletonContext.VisitAllModulesIf(predAdaptor(pred), visitAdaptor(visit)) 211} 212 213func (s *singletonContextAdaptor) VisitDirectDeps(module Module, visit func(Module)) { 214 s.SingletonContext.VisitDirectDeps(module, visitAdaptor(visit)) 215} 216 217func (s *singletonContextAdaptor) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) { 218 s.SingletonContext.VisitDirectDepsIf(module, predAdaptor(pred), visitAdaptor(visit)) 219} 220 221func (s *singletonContextAdaptor) VisitDepsDepthFirst(module Module, visit func(Module)) { 222 s.SingletonContext.VisitDepsDepthFirst(module, visitAdaptor(visit)) 223} 224 225func (s *singletonContextAdaptor) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) { 226 s.SingletonContext.VisitDepsDepthFirstIf(module, predAdaptor(pred), visitAdaptor(visit)) 227} 228 229func (s *singletonContextAdaptor) VisitAllModuleVariants(module Module, visit func(Module)) { 230 s.SingletonContext.VisitAllModuleVariants(module, visitAdaptor(visit)) 231} 232 233func (s *singletonContextAdaptor) PrimaryModule(module Module) Module { 234 return s.SingletonContext.PrimaryModule(module).(Module) 235} 236 237func (s *singletonContextAdaptor) FinalModule(module Module) Module { 238 return s.SingletonContext.FinalModule(module).(Module) 239} 240