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 15 package blueprint 16 17 import ( 18 "fmt" 19 "github.com/google/blueprint/pathtools" 20 ) 21 22 type Singleton interface { 23 GenerateBuildActions(SingletonContext) 24 } 25 26 type SingletonContext interface { 27 Config() interface{} 28 29 ModuleName(module Module) string 30 ModuleDir(module Module) string 31 ModuleSubDir(module Module) string 32 ModuleType(module Module) string 33 BlueprintFile(module Module) string 34 35 ModuleErrorf(module Module, format string, args ...interface{}) 36 Errorf(format string, args ...interface{}) 37 Failed() bool 38 39 Variable(pctx PackageContext, name, value string) 40 Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule 41 Build(pctx PackageContext, params BuildParams) 42 RequireNinjaVersion(major, minor, micro int) 43 44 // SetNinjaBuildDir sets the value of the top-level "builddir" Ninja variable 45 // that controls where Ninja stores its build log files. This value can be 46 // set at most one time for a single build, later calls are ignored. 47 SetNinjaBuildDir(pctx PackageContext, value string) 48 49 // Eval takes a string with embedded ninja variables, and returns a string 50 // with all of the variables recursively expanded. Any variables references 51 // are expanded in the scope of the PackageContext. 52 Eval(pctx PackageContext, ninjaStr string) (string, error) 53 54 VisitAllModules(visit func(Module)) 55 VisitAllModulesIf(pred func(Module) bool, visit func(Module)) 56 VisitDepsDepthFirst(module Module, visit func(Module)) 57 VisitDepsDepthFirstIf(module Module, pred func(Module) bool, 58 visit func(Module)) 59 60 VisitAllModuleVariants(module Module, visit func(Module)) 61 62 PrimaryModule(module Module) Module 63 FinalModule(module Module) Module 64 65 AddNinjaFileDeps(deps ...string) 66 67 // GlobWithDeps returns a list of files that match the specified pattern but do not match any 68 // of the patterns in excludes. It also adds efficient dependencies to rerun the primary 69 // builder whenever a file matching the pattern as added or removed, without rerunning if a 70 // file that does not match the pattern is added to a searched directory. 71 GlobWithDeps(pattern string, excludes []string) ([]string, error) 72 73 Fs() pathtools.FileSystem 74 } 75 76 var _ SingletonContext = (*singletonContext)(nil) 77 78 type singletonContext struct { 79 context *Context 80 config interface{} 81 scope *localScope 82 globals *liveTracker 83 84 ninjaFileDeps []string 85 errs []error 86 87 actionDefs localBuildActions 88 } 89 90 func (s *singletonContext) Config() interface{} { 91 return s.config 92 } 93 94 func (s *singletonContext) ModuleName(logicModule Module) string { 95 return s.context.ModuleName(logicModule) 96 } 97 98 func (s *singletonContext) ModuleDir(logicModule Module) string { 99 return s.context.ModuleDir(logicModule) 100 } 101 102 func (s *singletonContext) ModuleSubDir(logicModule Module) string { 103 return s.context.ModuleSubDir(logicModule) 104 } 105 106 func (s *singletonContext) ModuleType(logicModule Module) string { 107 return s.context.ModuleType(logicModule) 108 } 109 110 func (s *singletonContext) BlueprintFile(logicModule Module) string { 111 return s.context.BlueprintFile(logicModule) 112 } 113 114 func (s *singletonContext) error(err error) { 115 if err != nil { 116 s.errs = append(s.errs, err) 117 } 118 } 119 120 func (s *singletonContext) ModuleErrorf(logicModule Module, format string, 121 args ...interface{}) { 122 123 s.error(s.context.ModuleErrorf(logicModule, format, args...)) 124 } 125 126 func (s *singletonContext) Errorf(format string, args ...interface{}) { 127 // TODO: Make this not result in the error being printed as "internal error" 128 s.error(fmt.Errorf(format, args...)) 129 } 130 131 func (s *singletonContext) Failed() bool { 132 return len(s.errs) > 0 133 } 134 135 func (s *singletonContext) Variable(pctx PackageContext, name, value string) { 136 s.scope.ReparentTo(pctx) 137 138 v, err := s.scope.AddLocalVariable(name, value) 139 if err != nil { 140 panic(err) 141 } 142 143 s.actionDefs.variables = append(s.actionDefs.variables, v) 144 } 145 146 func (s *singletonContext) Rule(pctx PackageContext, name string, 147 params RuleParams, argNames ...string) Rule { 148 149 s.scope.ReparentTo(pctx) 150 151 r, err := s.scope.AddLocalRule(name, ¶ms, argNames...) 152 if err != nil { 153 panic(err) 154 } 155 156 s.actionDefs.rules = append(s.actionDefs.rules, r) 157 158 return r 159 } 160 161 func (s *singletonContext) Build(pctx PackageContext, params BuildParams) { 162 s.scope.ReparentTo(pctx) 163 164 def, err := parseBuildParams(s.scope, ¶ms) 165 if err != nil { 166 panic(err) 167 } 168 169 s.actionDefs.buildDefs = append(s.actionDefs.buildDefs, def) 170 } 171 172 func (s *singletonContext) Eval(pctx PackageContext, str string) (string, error) { 173 s.scope.ReparentTo(pctx) 174 175 ninjaStr, err := parseNinjaString(s.scope, str) 176 if err != nil { 177 return "", err 178 } 179 180 err = s.globals.addNinjaStringDeps(ninjaStr) 181 if err != nil { 182 return "", err 183 } 184 185 return ninjaStr.Eval(s.globals.variables) 186 } 187 188 func (s *singletonContext) RequireNinjaVersion(major, minor, micro int) { 189 s.context.requireNinjaVersion(major, minor, micro) 190 } 191 192 func (s *singletonContext) SetNinjaBuildDir(pctx PackageContext, value string) { 193 s.scope.ReparentTo(pctx) 194 195 ninjaValue, err := parseNinjaString(s.scope, value) 196 if err != nil { 197 panic(err) 198 } 199 200 s.context.setNinjaBuildDir(ninjaValue) 201 } 202 203 func (s *singletonContext) VisitAllModules(visit func(Module)) { 204 s.context.VisitAllModules(visit) 205 } 206 207 func (s *singletonContext) VisitAllModulesIf(pred func(Module) bool, 208 visit func(Module)) { 209 210 s.context.VisitAllModulesIf(pred, visit) 211 } 212 213 func (s *singletonContext) VisitDepsDepthFirst(module Module, 214 visit func(Module)) { 215 216 s.context.VisitDepsDepthFirst(module, visit) 217 } 218 219 func (s *singletonContext) VisitDepsDepthFirstIf(module Module, 220 pred func(Module) bool, visit func(Module)) { 221 222 s.context.VisitDepsDepthFirstIf(module, pred, visit) 223 } 224 225 func (s *singletonContext) PrimaryModule(module Module) Module { 226 return s.context.PrimaryModule(module) 227 } 228 229 func (s *singletonContext) FinalModule(module Module) Module { 230 return s.context.FinalModule(module) 231 } 232 233 func (s *singletonContext) VisitAllModuleVariants(module Module, visit func(Module)) { 234 s.context.VisitAllModuleVariants(module, visit) 235 } 236 237 func (s *singletonContext) AddNinjaFileDeps(deps ...string) { 238 s.ninjaFileDeps = append(s.ninjaFileDeps, deps...) 239 } 240 241 func (s *singletonContext) GlobWithDeps(pattern string, 242 excludes []string) ([]string, error) { 243 return s.context.glob(pattern, excludes) 244 } 245 246 func (s *singletonContext) Fs() pathtools.FileSystem { 247 return s.context.fs 248 } 249