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 // ModuleVariantsFromName returns the list of module variants named `name` in the same namespace as `referer` enforcing visibility rules. 33 // Allows generating build actions for `referer` based on the metadata for `name` deferred until the singleton context. 34 ModuleVariantsFromName(referer Module, name string) []Module 35 36 // ModuleProvider returns the value, if any, for the provider for a module. If the value for the 37 // provider was not set it returns the zero value of the type of the provider, which means the 38 // return value can always be type-asserted to the type of the provider. The return value should 39 // always be considered read-only. It panics if called before the appropriate mutator or 40 // GenerateBuildActions pass for the provider on the module. 41 ModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{} 42 43 // ModuleHasProvider returns true if the provider for the given module has been set. 44 ModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool 45 46 ModuleErrorf(module blueprint.Module, format string, args ...interface{}) 47 Errorf(format string, args ...interface{}) 48 Failed() bool 49 50 Variable(pctx PackageContext, name, value string) 51 Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule 52 Build(pctx PackageContext, params BuildParams) 53 54 // Phony creates a Make-style phony rule, a rule with no commands that can depend on other 55 // phony rules or real files. Phony can be called on the same name multiple times to add 56 // additional dependencies. 57 Phony(name string, deps ...Path) 58 59 RequireNinjaVersion(major, minor, micro int) 60 61 // SetOutDir sets the value of the top-level "builddir" Ninja variable 62 // that controls where Ninja stores its build log files. This value can be 63 // set at most one time for a single build, later calls are ignored. 64 SetOutDir(pctx PackageContext, value string) 65 66 // Eval takes a string with embedded ninja variables, and returns a string 67 // with all of the variables recursively expanded. Any variables references 68 // are expanded in the scope of the PackageContext. 69 Eval(pctx PackageContext, ninjaStr string) (string, error) 70 71 VisitAllModulesBlueprint(visit func(blueprint.Module)) 72 VisitAllModules(visit func(Module)) 73 VisitAllModulesIf(pred func(Module) bool, visit func(Module)) 74 75 VisitDirectDeps(module Module, visit func(Module)) 76 VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) 77 78 // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module 79 VisitDepsDepthFirst(module Module, visit func(Module)) 80 // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module 81 VisitDepsDepthFirstIf(module Module, pred func(Module) bool, 82 visit func(Module)) 83 84 VisitAllModuleVariants(module Module, visit func(Module)) 85 86 PrimaryModule(module Module) Module 87 FinalModule(module Module) Module 88 89 AddNinjaFileDeps(deps ...string) 90 91 // GlobWithDeps returns a list of files that match the specified pattern but do not match any 92 // of the patterns in excludes. It also adds efficient dependencies to rerun the primary 93 // builder whenever a file matching the pattern as added or removed, without rerunning if a 94 // file that does not match the pattern is added to a searched directory. 95 GlobWithDeps(pattern string, excludes []string) ([]string, error) 96} 97 98type singletonAdaptor struct { 99 Singleton 100 101 buildParams []BuildParams 102 ruleParams map[blueprint.Rule]blueprint.RuleParams 103} 104 105var _ testBuildProvider = (*singletonAdaptor)(nil) 106 107func (s *singletonAdaptor) GenerateBuildActions(ctx blueprint.SingletonContext) { 108 sctx := &singletonContextAdaptor{SingletonContext: ctx} 109 if sctx.Config().captureBuild { 110 sctx.ruleParams = make(map[blueprint.Rule]blueprint.RuleParams) 111 } 112 113 s.Singleton.GenerateBuildActions(sctx) 114 115 s.buildParams = sctx.buildParams 116 s.ruleParams = sctx.ruleParams 117} 118 119func (s *singletonAdaptor) BuildParamsForTests() []BuildParams { 120 return s.buildParams 121} 122 123func (s *singletonAdaptor) RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams { 124 return s.ruleParams 125} 126 127type Singleton interface { 128 GenerateBuildActions(SingletonContext) 129} 130 131type singletonContextAdaptor struct { 132 blueprint.SingletonContext 133 134 buildParams []BuildParams 135 ruleParams map[blueprint.Rule]blueprint.RuleParams 136} 137 138func (s *singletonContextAdaptor) Config() Config { 139 return s.SingletonContext.Config().(Config) 140} 141 142func (s *singletonContextAdaptor) DeviceConfig() DeviceConfig { 143 return DeviceConfig{s.Config().deviceConfig} 144} 145 146func (s *singletonContextAdaptor) Variable(pctx PackageContext, name, value string) { 147 s.SingletonContext.Variable(pctx.PackageContext, name, value) 148} 149 150func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule { 151 if s.Config().UseRemoteBuild() { 152 if params.Pool == nil { 153 // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict 154 // jobs to the local parallelism value 155 params.Pool = localPool 156 } else if params.Pool == remotePool { 157 // remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's 158 // pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS 159 // parallelism. 160 params.Pool = nil 161 } 162 } 163 rule := s.SingletonContext.Rule(pctx.PackageContext, name, params, argNames...) 164 if s.Config().captureBuild { 165 s.ruleParams[rule] = params 166 } 167 return rule 168} 169 170func (s *singletonContextAdaptor) Build(pctx PackageContext, params BuildParams) { 171 if s.Config().captureBuild { 172 s.buildParams = append(s.buildParams, params) 173 } 174 bparams := convertBuildParams(params) 175 err := validateBuildParams(bparams) 176 if err != nil { 177 s.Errorf("%s: build parameter validation failed: %s", s.Name(), err.Error()) 178 } 179 s.SingletonContext.Build(pctx.PackageContext, bparams) 180 181} 182 183func (s *singletonContextAdaptor) Phony(name string, deps ...Path) { 184 addPhony(s.Config(), name, deps...) 185} 186 187func (s *singletonContextAdaptor) SetOutDir(pctx PackageContext, value string) { 188 s.SingletonContext.SetOutDir(pctx.PackageContext, value) 189} 190 191func (s *singletonContextAdaptor) Eval(pctx PackageContext, ninjaStr string) (string, error) { 192 return s.SingletonContext.Eval(pctx.PackageContext, ninjaStr) 193} 194 195// visitAdaptor wraps a visit function that takes an android.Module parameter into 196// a function that takes an blueprint.Module parameter and only calls the visit function if the 197// blueprint.Module is an android.Module. 198func visitAdaptor(visit func(Module)) func(blueprint.Module) { 199 return func(module blueprint.Module) { 200 if aModule, ok := module.(Module); ok { 201 visit(aModule) 202 } 203 } 204} 205 206// predAdaptor wraps a pred function that takes an android.Module parameter 207// into a function that takes an blueprint.Module parameter and only calls the visit function if the 208// blueprint.Module is an android.Module, otherwise returns false. 209func predAdaptor(pred func(Module) bool) func(blueprint.Module) bool { 210 return func(module blueprint.Module) bool { 211 if aModule, ok := module.(Module); ok { 212 return pred(aModule) 213 } else { 214 return false 215 } 216 } 217} 218 219func (s *singletonContextAdaptor) VisitAllModulesBlueprint(visit func(blueprint.Module)) { 220 s.SingletonContext.VisitAllModules(visit) 221} 222 223func (s *singletonContextAdaptor) VisitAllModules(visit func(Module)) { 224 s.SingletonContext.VisitAllModules(visitAdaptor(visit)) 225} 226 227func (s *singletonContextAdaptor) VisitAllModulesIf(pred func(Module) bool, visit func(Module)) { 228 s.SingletonContext.VisitAllModulesIf(predAdaptor(pred), visitAdaptor(visit)) 229} 230 231func (s *singletonContextAdaptor) VisitDirectDeps(module Module, visit func(Module)) { 232 s.SingletonContext.VisitDirectDeps(module, visitAdaptor(visit)) 233} 234 235func (s *singletonContextAdaptor) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) { 236 s.SingletonContext.VisitDirectDepsIf(module, predAdaptor(pred), visitAdaptor(visit)) 237} 238 239func (s *singletonContextAdaptor) VisitDepsDepthFirst(module Module, visit func(Module)) { 240 s.SingletonContext.VisitDepsDepthFirst(module, visitAdaptor(visit)) 241} 242 243func (s *singletonContextAdaptor) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) { 244 s.SingletonContext.VisitDepsDepthFirstIf(module, predAdaptor(pred), visitAdaptor(visit)) 245} 246 247func (s *singletonContextAdaptor) VisitAllModuleVariants(module Module, visit func(Module)) { 248 s.SingletonContext.VisitAllModuleVariants(module, visitAdaptor(visit)) 249} 250 251func (s *singletonContextAdaptor) PrimaryModule(module Module) Module { 252 return s.SingletonContext.PrimaryModule(module).(Module) 253} 254 255func (s *singletonContextAdaptor) FinalModule(module Module) Module { 256 return s.SingletonContext.FinalModule(module).(Module) 257} 258 259func (s *singletonContextAdaptor) ModuleVariantsFromName(referer Module, name string) []Module { 260 // get qualified module name for visibility enforcement 261 qualified := createQualifiedModuleName(s.ModuleName(referer), s.ModuleDir(referer)) 262 263 modules := s.SingletonContext.ModuleVariantsFromName(referer, name) 264 result := make([]Module, 0, len(modules)) 265 for _, m := range modules { 266 if module, ok := m.(Module); ok { 267 // enforce visibility 268 depName := s.ModuleName(module) 269 depDir := s.ModuleDir(module) 270 depQualified := qualifiedModuleName{depDir, depName} 271 // Targets are always visible to other targets in their own package. 272 if depQualified.pkg != qualified.pkg { 273 rule := effectiveVisibilityRules(s.Config(), depQualified) 274 if !rule.matches(qualified) { 275 s.ModuleErrorf(referer, "module %q references %q which is not visible to this module\nYou may need to add %q to its visibility", 276 referer.Name(), depQualified, "//"+s.ModuleDir(referer)) 277 continue 278 } 279 } 280 result = append(result, module) 281 } 282 } 283 return result 284} 285