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 blueprintSingletonContext() blueprint.SingletonContext 24 25 Config() Config 26 DeviceConfig() DeviceConfig 27 28 ModuleName(module blueprint.Module) string 29 ModuleDir(module blueprint.Module) string 30 ModuleSubDir(module blueprint.Module) string 31 ModuleType(module blueprint.Module) string 32 BlueprintFile(module blueprint.Module) string 33 34 // ModuleVariantsFromName returns the list of module variants named `name` in the same namespace as `referer` enforcing visibility rules. 35 // Allows generating build actions for `referer` based on the metadata for `name` deferred until the singleton context. 36 ModuleVariantsFromName(referer Module, name string) []Module 37 38 moduleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) 39 40 ModuleErrorf(module blueprint.Module, format string, args ...interface{}) 41 Errorf(format string, args ...interface{}) 42 Failed() bool 43 44 Variable(pctx PackageContext, name, value string) 45 Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule 46 Build(pctx PackageContext, params BuildParams) 47 48 // Phony creates a Make-style phony rule, a rule with no commands that can depend on other 49 // phony rules or real files. Phony can be called on the same name multiple times to add 50 // additional dependencies. 51 Phony(name string, deps ...Path) 52 53 RequireNinjaVersion(major, minor, micro int) 54 55 // SetOutDir sets the value of the top-level "builddir" Ninja variable 56 // that controls where Ninja stores its build log files. This value can be 57 // set at most one time for a single build, later calls are ignored. 58 SetOutDir(pctx PackageContext, value string) 59 60 // Eval takes a string with embedded ninja variables, and returns a string 61 // with all of the variables recursively expanded. Any variables references 62 // are expanded in the scope of the PackageContext. 63 Eval(pctx PackageContext, ninjaStr string) (string, error) 64 65 VisitAllModulesBlueprint(visit func(blueprint.Module)) 66 VisitAllModules(visit func(Module)) 67 VisitAllModulesIf(pred func(Module) bool, visit func(Module)) 68 69 VisitDirectDeps(module Module, visit func(Module)) 70 VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) 71 72 // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module 73 VisitDepsDepthFirst(module Module, visit func(Module)) 74 // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module 75 VisitDepsDepthFirstIf(module Module, pred func(Module) bool, 76 visit func(Module)) 77 78 VisitAllModuleVariants(module Module, visit func(Module)) 79 80 PrimaryModule(module Module) Module 81 FinalModule(module Module) Module 82 83 AddNinjaFileDeps(deps ...string) 84 85 // GlobWithDeps returns a list of files that match the specified pattern but do not match any 86 // of the patterns in excludes. It also adds efficient dependencies to rerun the primary 87 // builder whenever a file matching the pattern as added or removed, without rerunning if a 88 // file that does not match the pattern is added to a searched directory. 89 GlobWithDeps(pattern string, excludes []string) ([]string, error) 90 91 // OtherModulePropertyErrorf reports an error on the line number of the given property of the given module 92 OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{}) 93} 94 95type singletonAdaptor struct { 96 Singleton 97 98 buildParams []BuildParams 99 ruleParams map[blueprint.Rule]blueprint.RuleParams 100} 101 102var _ testBuildProvider = (*singletonAdaptor)(nil) 103 104func (s *singletonAdaptor) GenerateBuildActions(ctx blueprint.SingletonContext) { 105 sctx := &singletonContextAdaptor{SingletonContext: ctx} 106 if sctx.Config().captureBuild { 107 sctx.ruleParams = make(map[blueprint.Rule]blueprint.RuleParams) 108 } 109 110 s.Singleton.GenerateBuildActions(sctx) 111 112 s.buildParams = sctx.buildParams 113 s.ruleParams = sctx.ruleParams 114} 115 116func (s *singletonAdaptor) BuildParamsForTests() []BuildParams { 117 return s.buildParams 118} 119 120func (s *singletonAdaptor) RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams { 121 return s.ruleParams 122} 123 124type Singleton interface { 125 GenerateBuildActions(SingletonContext) 126} 127 128type singletonContextAdaptor struct { 129 blueprint.SingletonContext 130 131 buildParams []BuildParams 132 ruleParams map[blueprint.Rule]blueprint.RuleParams 133} 134 135func (s *singletonContextAdaptor) blueprintSingletonContext() blueprint.SingletonContext { 136 return s.SingletonContext 137} 138 139func (s *singletonContextAdaptor) Config() Config { 140 return s.SingletonContext.Config().(Config) 141} 142 143func (s *singletonContextAdaptor) DeviceConfig() DeviceConfig { 144 return DeviceConfig{s.Config().deviceConfig} 145} 146 147func (s *singletonContextAdaptor) Variable(pctx PackageContext, name, value string) { 148 s.SingletonContext.Variable(pctx.PackageContext, name, value) 149} 150 151func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule { 152 if s.Config().UseRemoteBuild() { 153 if params.Pool == nil { 154 // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict 155 // jobs to the local parallelism value 156 params.Pool = localPool 157 } else if params.Pool == remotePool { 158 // remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's 159 // pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS 160 // parallelism. 161 params.Pool = nil 162 } 163 } 164 rule := s.SingletonContext.Rule(pctx.PackageContext, name, params, argNames...) 165 if s.Config().captureBuild { 166 s.ruleParams[rule] = params 167 } 168 return rule 169} 170 171func (s *singletonContextAdaptor) Build(pctx PackageContext, params BuildParams) { 172 if s.Config().captureBuild { 173 s.buildParams = append(s.buildParams, params) 174 } 175 bparams := convertBuildParams(params) 176 s.SingletonContext.Build(pctx.PackageContext, bparams) 177} 178 179func (s *singletonContextAdaptor) Phony(name string, deps ...Path) { 180 addPhony(s.Config(), name, deps...) 181} 182 183func (s *singletonContextAdaptor) SetOutDir(pctx PackageContext, value string) { 184 s.SingletonContext.SetOutDir(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 255func (s *singletonContextAdaptor) ModuleVariantsFromName(referer Module, name string) []Module { 256 // get module reference for visibility enforcement 257 qualified := createVisibilityModuleReference(s.ModuleName(referer), s.ModuleDir(referer), referer) 258 259 modules := s.SingletonContext.ModuleVariantsFromName(referer, name) 260 result := make([]Module, 0, len(modules)) 261 for _, m := range modules { 262 if module, ok := m.(Module); ok { 263 // enforce visibility 264 depName := s.ModuleName(module) 265 depDir := s.ModuleDir(module) 266 depQualified := qualifiedModuleName{depDir, depName} 267 // Targets are always visible to other targets in their own package. 268 if depQualified.pkg != qualified.name.pkg { 269 rule := effectiveVisibilityRules(s.Config(), depQualified) 270 if !rule.matches(qualified) { 271 s.ModuleErrorf(referer, "module %q references %q which is not visible to this module\nYou may need to add %q to its visibility", 272 referer.Name(), depQualified, "//"+s.ModuleDir(referer)) 273 continue 274 } 275 } 276 result = append(result, module) 277 } 278 } 279 return result 280} 281 282func (s *singletonContextAdaptor) moduleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) { 283 return s.SingletonContext.ModuleProvider(module, provider) 284} 285 286func (s *singletonContextAdaptor) OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{}) { 287 s.blueprintSingletonContext().OtherModulePropertyErrorf(module, property, format, args...) 288} 289