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() interface{} 29 30 Name() string 31 32 ModuleName(module Module) string 33 ModuleDir(module Module) string 34 ModuleSubDir(module Module) string 35 ModuleType(module Module) string 36 BlueprintFile(module Module) string 37 38 ModuleErrorf(module Module, format string, args ...interface{}) 39 Errorf(format string, args ...interface{}) 40 Failed() bool 41 42 Variable(pctx PackageContext, name, value string) 43 Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule 44 Build(pctx PackageContext, params BuildParams) 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 // AddSubninja adds a ninja file to include with subninja. This should likely 53 // only ever be used inside bootstrap to handle glob rules. 54 AddSubninja(file string) 55 56 // Eval takes a string with embedded ninja variables, and returns a string 57 // with all of the variables recursively expanded. Any variables references 58 // are expanded in the scope of the PackageContext. 59 Eval(pctx PackageContext, ninjaStr string) (string, error) 60 61 VisitAllModules(visit func(Module)) 62 VisitAllModulesIf(pred func(Module) bool, visit func(Module)) 63 VisitDepsDepthFirst(module Module, visit func(Module)) 64 VisitDepsDepthFirstIf(module Module, pred func(Module) bool, 65 visit func(Module)) 66 67 VisitAllModuleVariants(module Module, visit func(Module)) 68 69 PrimaryModule(module Module) Module 70 FinalModule(module Module) Module 71 72 AddNinjaFileDeps(deps ...string) 73 74 // GlobWithDeps returns a list of files and directories that match the 75 // specified pattern but do not match any of the patterns in excludes. 76 // Any directories will have a '/' suffix. It also adds efficient 77 // dependencies to rerun the primary builder whenever a file matching 78 // the pattern as added or removed, without rerunning if a file that 79 // does not match the pattern is added to a searched directory. 80 GlobWithDeps(pattern string, excludes []string) ([]string, error) 81 82 Fs() pathtools.FileSystem 83} 84 85var _ SingletonContext = (*singletonContext)(nil) 86 87type singletonContext struct { 88 name string 89 context *Context 90 config interface{} 91 scope *localScope 92 globals *liveTracker 93 94 ninjaFileDeps []string 95 errs []error 96 97 actionDefs localBuildActions 98} 99 100func (s *singletonContext) Config() interface{} { 101 return s.config 102} 103 104func (s *singletonContext) Name() string { 105 return s.name 106} 107 108func (s *singletonContext) ModuleName(logicModule Module) string { 109 return s.context.ModuleName(logicModule) 110} 111 112func (s *singletonContext) ModuleDir(logicModule Module) string { 113 return s.context.ModuleDir(logicModule) 114} 115 116func (s *singletonContext) ModuleSubDir(logicModule Module) string { 117 return s.context.ModuleSubDir(logicModule) 118} 119 120func (s *singletonContext) ModuleType(logicModule Module) string { 121 return s.context.ModuleType(logicModule) 122} 123 124func (s *singletonContext) BlueprintFile(logicModule Module) string { 125 return s.context.BlueprintFile(logicModule) 126} 127 128func (s *singletonContext) error(err error) { 129 if err != nil { 130 s.errs = append(s.errs, err) 131 } 132} 133 134func (s *singletonContext) ModuleErrorf(logicModule Module, format string, 135 args ...interface{}) { 136 137 s.error(s.context.ModuleErrorf(logicModule, format, args...)) 138} 139 140func (s *singletonContext) Errorf(format string, args ...interface{}) { 141 // TODO: Make this not result in the error being printed as "internal error" 142 s.error(fmt.Errorf(format, args...)) 143} 144 145func (s *singletonContext) Failed() bool { 146 return len(s.errs) > 0 147} 148 149func (s *singletonContext) Variable(pctx PackageContext, name, value string) { 150 s.scope.ReparentTo(pctx) 151 152 v, err := s.scope.AddLocalVariable(name, value) 153 if err != nil { 154 panic(err) 155 } 156 157 s.actionDefs.variables = append(s.actionDefs.variables, v) 158} 159 160func (s *singletonContext) Rule(pctx PackageContext, name string, 161 params RuleParams, argNames ...string) Rule { 162 163 s.scope.ReparentTo(pctx) 164 165 r, err := s.scope.AddLocalRule(name, ¶ms, argNames...) 166 if err != nil { 167 panic(err) 168 } 169 170 s.actionDefs.rules = append(s.actionDefs.rules, r) 171 172 return r 173} 174 175func (s *singletonContext) Build(pctx PackageContext, params BuildParams) { 176 s.scope.ReparentTo(pctx) 177 178 def, err := parseBuildParams(s.scope, ¶ms) 179 if err != nil { 180 panic(err) 181 } 182 183 s.actionDefs.buildDefs = append(s.actionDefs.buildDefs, def) 184} 185 186func (s *singletonContext) Eval(pctx PackageContext, str string) (string, error) { 187 s.scope.ReparentTo(pctx) 188 189 ninjaStr, err := parseNinjaString(s.scope, str) 190 if err != nil { 191 return "", err 192 } 193 194 err = s.globals.addNinjaStringDeps(ninjaStr) 195 if err != nil { 196 return "", err 197 } 198 199 return ninjaStr.Eval(s.globals.variables) 200} 201 202func (s *singletonContext) RequireNinjaVersion(major, minor, micro int) { 203 s.context.requireNinjaVersion(major, minor, micro) 204} 205 206func (s *singletonContext) SetNinjaBuildDir(pctx PackageContext, value string) { 207 s.scope.ReparentTo(pctx) 208 209 ninjaValue, err := parseNinjaString(s.scope, value) 210 if err != nil { 211 panic(err) 212 } 213 214 s.context.setNinjaBuildDir(ninjaValue) 215} 216 217func (s *singletonContext) AddSubninja(file string) { 218 s.context.subninjas = append(s.context.subninjas, file) 219} 220 221func (s *singletonContext) VisitAllModules(visit func(Module)) { 222 var visitingModule Module 223 defer func() { 224 if r := recover(); r != nil { 225 panic(newPanicErrorf(r, "VisitAllModules(%s) for module %s", 226 funcName(visit), visitingModule)) 227 } 228 }() 229 230 s.context.VisitAllModules(func(m Module) { 231 visitingModule = m 232 visit(m) 233 }) 234} 235 236func (s *singletonContext) VisitAllModulesIf(pred func(Module) bool, 237 visit func(Module)) { 238 239 s.context.VisitAllModulesIf(pred, visit) 240} 241 242func (s *singletonContext) VisitDepsDepthFirst(module Module, 243 visit func(Module)) { 244 245 s.context.VisitDepsDepthFirst(module, visit) 246} 247 248func (s *singletonContext) VisitDepsDepthFirstIf(module Module, 249 pred func(Module) bool, visit func(Module)) { 250 251 s.context.VisitDepsDepthFirstIf(module, pred, visit) 252} 253 254func (s *singletonContext) PrimaryModule(module Module) Module { 255 return s.context.PrimaryModule(module) 256} 257 258func (s *singletonContext) FinalModule(module Module) Module { 259 return s.context.FinalModule(module) 260} 261 262func (s *singletonContext) VisitAllModuleVariants(module Module, visit func(Module)) { 263 s.context.VisitAllModuleVariants(module, visit) 264} 265 266func (s *singletonContext) AddNinjaFileDeps(deps ...string) { 267 s.ninjaFileDeps = append(s.ninjaFileDeps, deps...) 268} 269 270func (s *singletonContext) GlobWithDeps(pattern string, 271 excludes []string) ([]string, error) { 272 return s.context.glob(pattern, excludes) 273} 274 275func (s *singletonContext) Fs() pathtools.FileSystem { 276 return s.context.fs 277} 278