1// Copyright 2014 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 blueprint 16 17import ( 18 "fmt" 19 20 "github.com/google/blueprint/pathtools" 21) 22 23type Singleton interface { 24 GenerateBuildActions(SingletonContext) 25} 26 27type SingletonContext interface { 28 // Config returns the config object that was passed to Context.PrepareBuildActions. 29 Config() interface{} 30 31 // Name returns the name of the current singleton passed to Context.RegisterSingletonType 32 Name() string 33 34 // ModuleName returns the name of the given Module. See BaseModuleContext.ModuleName for more information. 35 ModuleName(module Module) string 36 37 // ModuleDir returns the directory of the given Module. See BaseModuleContext.ModuleDir for more information. 38 ModuleDir(module Module) string 39 40 // ModuleSubDir returns the unique subdirectory name of the given Module. See ModuleContext.ModuleSubDir for 41 // more information. 42 ModuleSubDir(module Module) string 43 44 // ModuleType returns the type of the given Module. See BaseModuleContext.ModuleType for more information. 45 ModuleType(module Module) string 46 47 // BlueprintFile returns the path of the Blueprint file that defined the given module. 48 BlueprintFile(module Module) string 49 50 // ModuleErrorf reports an error at the line number of the module type in the module definition. 51 ModuleErrorf(module Module, format string, args ...interface{}) 52 53 // Errorf reports an error at the specified position of the module definition file. 54 Errorf(format string, args ...interface{}) 55 56 // Failed returns true if any errors have been reported. In most cases the singleton can continue with generating 57 // build rules after an error, allowing it to report additional errors in a single run, but in cases where the error 58 // has prevented the singleton from creating necessary data it can return early when Failed returns true. 59 Failed() bool 60 61 // Variable creates a new ninja variable scoped to the singleton. It can be referenced by calls to Rule and Build 62 // in the same singleton. 63 Variable(pctx PackageContext, name, value string) 64 65 // Rule creates a new ninja rule scoped to the singleton. It can be referenced by calls to Build in the same 66 // singleton. 67 Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule 68 69 // Build creates a new ninja build statement. 70 Build(pctx PackageContext, params BuildParams) 71 72 // RequireNinjaVersion sets the generated ninja manifest to require at least the specified version of ninja. 73 RequireNinjaVersion(major, minor, micro int) 74 75 // SetNinjaBuildDir sets the value of the top-level "builddir" Ninja variable 76 // that controls where Ninja stores its build log files. This value can be 77 // set at most one time for a single build, later calls are ignored. 78 SetNinjaBuildDir(pctx PackageContext, value string) 79 80 // AddSubninja adds a ninja file to include with subninja. This should likely 81 // only ever be used inside bootstrap to handle glob rules. 82 AddSubninja(file string) 83 84 // Eval takes a string with embedded ninja variables, and returns a string 85 // with all of the variables recursively expanded. Any variables references 86 // are expanded in the scope of the PackageContext. 87 Eval(pctx PackageContext, ninjaStr string) (string, error) 88 89 // VisitAllModules calls visit for each defined variant of each module in an unspecified order. 90 VisitAllModules(visit func(Module)) 91 92 // VisitAllModules calls pred for each defined variant of each module in an unspecified order, and if pred returns 93 // true calls visit. 94 VisitAllModulesIf(pred func(Module) bool, visit func(Module)) 95 96 // VisitDirectDeps calls visit for each direct dependency of the Module. If there are 97 // multiple direct dependencies on the same module visit will be called multiple times on 98 // that module and OtherModuleDependencyTag will return a different tag for each. 99 // 100 // The Module passed to the visit function should not be retained outside of the visit 101 // function, it may be invalidated by future mutators. 102 VisitDirectDeps(module Module, visit func(Module)) 103 104 // VisitDirectDepsIf calls pred for each direct dependency of the Module, and if pred 105 // returns true calls visit. If there are multiple direct dependencies on the same module 106 // pred and visit will be called multiple times on that module and OtherModuleDependencyTag 107 // will return a different tag for each. 108 // 109 // The Module passed to the visit function should not be retained outside of the visit 110 // function, it may be invalidated by future mutators. 111 VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) 112 113 // VisitDepsDepthFirst calls visit for each transitive dependency, traversing the dependency tree in depth first 114 // order. visit will only be called once for any given module, even if there are multiple paths through the 115 // dependency tree to the module or multiple direct dependencies with different tags. 116 VisitDepsDepthFirst(module Module, visit func(Module)) 117 118 // VisitDepsDepthFirst calls pred for each transitive dependency, and if pred returns true calls visit, traversing 119 // the dependency tree in depth first order. visit will only be called once for any given module, even if there are 120 // multiple paths through the dependency tree to the module or multiple direct dependencies with different tags. 121 VisitDepsDepthFirstIf(module Module, pred func(Module) bool, 122 visit func(Module)) 123 124 // VisitAllModuleVariants calls visit for each variant of the given module. 125 VisitAllModuleVariants(module Module, visit func(Module)) 126 127 // PrimaryModule returns the first variant of the given module. This can be used to perform 128 // // singleton actions that are only done once for all variants of a module. 129 PrimaryModule(module Module) Module 130 131 // FinalModule returns the last variant of the given module. This can be used to perform 132 // singleton actions that are only done once for all variants of a module. 133 FinalModule(module Module) Module 134 135 // AddNinjaFileDeps adds dependencies on the specified files to the rule that creates the ninja manifest. The 136 // primary builder will be rerun whenever the specified files are modified. 137 AddNinjaFileDeps(deps ...string) 138 139 // GlobWithDeps returns a list of files and directories that match the 140 // specified pattern but do not match any of the patterns in excludes. 141 // Any directories will have a '/' suffix. It also adds efficient 142 // dependencies to rerun the primary builder whenever a file matching 143 // the pattern as added or removed, without rerunning if a file that 144 // does not match the pattern is added to a searched directory. 145 GlobWithDeps(pattern string, excludes []string) ([]string, error) 146 147 // Fs returns a pathtools.Filesystem that can be used to interact with files. Using the Filesystem interface allows 148 // the singleton to be used in build system tests that run against a mock filesystem. 149 Fs() pathtools.FileSystem 150} 151 152var _ SingletonContext = (*singletonContext)(nil) 153 154type singletonContext struct { 155 name string 156 context *Context 157 config interface{} 158 scope *localScope 159 globals *liveTracker 160 161 ninjaFileDeps []string 162 errs []error 163 164 actionDefs localBuildActions 165} 166 167func (s *singletonContext) Config() interface{} { 168 return s.config 169} 170 171func (s *singletonContext) Name() string { 172 return s.name 173} 174 175func (s *singletonContext) ModuleName(logicModule Module) string { 176 return s.context.ModuleName(logicModule) 177} 178 179func (s *singletonContext) ModuleDir(logicModule Module) string { 180 return s.context.ModuleDir(logicModule) 181} 182 183func (s *singletonContext) ModuleSubDir(logicModule Module) string { 184 return s.context.ModuleSubDir(logicModule) 185} 186 187func (s *singletonContext) ModuleType(logicModule Module) string { 188 return s.context.ModuleType(logicModule) 189} 190 191func (s *singletonContext) BlueprintFile(logicModule Module) string { 192 return s.context.BlueprintFile(logicModule) 193} 194 195func (s *singletonContext) error(err error) { 196 if err != nil { 197 s.errs = append(s.errs, err) 198 } 199} 200 201func (s *singletonContext) ModuleErrorf(logicModule Module, format string, 202 args ...interface{}) { 203 204 s.error(s.context.ModuleErrorf(logicModule, format, args...)) 205} 206 207func (s *singletonContext) Errorf(format string, args ...interface{}) { 208 // TODO: Make this not result in the error being printed as "internal error" 209 s.error(fmt.Errorf(format, args...)) 210} 211 212func (s *singletonContext) Failed() bool { 213 return len(s.errs) > 0 214} 215 216func (s *singletonContext) Variable(pctx PackageContext, name, value string) { 217 s.scope.ReparentTo(pctx) 218 219 v, err := s.scope.AddLocalVariable(name, value) 220 if err != nil { 221 panic(err) 222 } 223 224 s.actionDefs.variables = append(s.actionDefs.variables, v) 225} 226 227func (s *singletonContext) Rule(pctx PackageContext, name string, 228 params RuleParams, argNames ...string) Rule { 229 230 s.scope.ReparentTo(pctx) 231 232 r, err := s.scope.AddLocalRule(name, ¶ms, argNames...) 233 if err != nil { 234 panic(err) 235 } 236 237 s.actionDefs.rules = append(s.actionDefs.rules, r) 238 239 return r 240} 241 242func (s *singletonContext) Build(pctx PackageContext, params BuildParams) { 243 s.scope.ReparentTo(pctx) 244 245 def, err := parseBuildParams(s.scope, ¶ms) 246 if err != nil { 247 panic(err) 248 } 249 250 s.actionDefs.buildDefs = append(s.actionDefs.buildDefs, def) 251} 252 253func (s *singletonContext) Eval(pctx PackageContext, str string) (string, error) { 254 s.scope.ReparentTo(pctx) 255 256 ninjaStr, err := parseNinjaString(s.scope, str) 257 if err != nil { 258 return "", err 259 } 260 261 err = s.globals.addNinjaStringDeps(ninjaStr) 262 if err != nil { 263 return "", err 264 } 265 266 return ninjaStr.Eval(s.globals.variables) 267} 268 269func (s *singletonContext) RequireNinjaVersion(major, minor, micro int) { 270 s.context.requireNinjaVersion(major, minor, micro) 271} 272 273func (s *singletonContext) SetNinjaBuildDir(pctx PackageContext, value string) { 274 s.scope.ReparentTo(pctx) 275 276 ninjaValue, err := parseNinjaString(s.scope, value) 277 if err != nil { 278 panic(err) 279 } 280 281 s.context.setNinjaBuildDir(ninjaValue) 282} 283 284func (s *singletonContext) AddSubninja(file string) { 285 s.context.subninjas = append(s.context.subninjas, file) 286} 287 288func (s *singletonContext) VisitAllModules(visit func(Module)) { 289 var visitingModule Module 290 defer func() { 291 if r := recover(); r != nil { 292 panic(newPanicErrorf(r, "VisitAllModules(%s) for module %s", 293 funcName(visit), s.context.moduleInfo[visitingModule])) 294 } 295 }() 296 297 s.context.VisitAllModules(func(m Module) { 298 visitingModule = m 299 visit(m) 300 }) 301} 302 303func (s *singletonContext) VisitAllModulesIf(pred func(Module) bool, 304 visit func(Module)) { 305 306 s.context.VisitAllModulesIf(pred, visit) 307} 308 309func (s *singletonContext) VisitDirectDeps(module Module, visit func(Module)) { 310 s.context.VisitDirectDeps(module, visit) 311} 312 313func (s *singletonContext) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) { 314 s.context.VisitDirectDepsIf(module, pred, visit) 315} 316 317func (s *singletonContext) VisitDepsDepthFirst(module Module, 318 visit func(Module)) { 319 320 s.context.VisitDepsDepthFirst(module, visit) 321} 322 323func (s *singletonContext) VisitDepsDepthFirstIf(module Module, 324 pred func(Module) bool, visit func(Module)) { 325 326 s.context.VisitDepsDepthFirstIf(module, pred, visit) 327} 328 329func (s *singletonContext) PrimaryModule(module Module) Module { 330 return s.context.PrimaryModule(module) 331} 332 333func (s *singletonContext) FinalModule(module Module) Module { 334 return s.context.FinalModule(module) 335} 336 337func (s *singletonContext) VisitAllModuleVariants(module Module, visit func(Module)) { 338 s.context.VisitAllModuleVariants(module, visit) 339} 340 341func (s *singletonContext) AddNinjaFileDeps(deps ...string) { 342 s.ninjaFileDeps = append(s.ninjaFileDeps, deps...) 343} 344 345func (s *singletonContext) GlobWithDeps(pattern string, 346 excludes []string) ([]string, error) { 347 return s.context.glob(pattern, excludes) 348} 349 350func (s *singletonContext) Fs() pathtools.FileSystem { 351 return s.context.fs 352} 353