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 "github.com/google/blueprint/pathtools" 20) 21 22type Singleton interface { 23 GenerateBuildActions(SingletonContext) 24} 25 26type 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 76var _ SingletonContext = (*singletonContext)(nil) 77 78type 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 90func (s *singletonContext) Config() interface{} { 91 return s.config 92} 93 94func (s *singletonContext) ModuleName(logicModule Module) string { 95 return s.context.ModuleName(logicModule) 96} 97 98func (s *singletonContext) ModuleDir(logicModule Module) string { 99 return s.context.ModuleDir(logicModule) 100} 101 102func (s *singletonContext) ModuleSubDir(logicModule Module) string { 103 return s.context.ModuleSubDir(logicModule) 104} 105 106func (s *singletonContext) ModuleType(logicModule Module) string { 107 return s.context.ModuleType(logicModule) 108} 109 110func (s *singletonContext) BlueprintFile(logicModule Module) string { 111 return s.context.BlueprintFile(logicModule) 112} 113 114func (s *singletonContext) error(err error) { 115 if err != nil { 116 s.errs = append(s.errs, err) 117 } 118} 119 120func (s *singletonContext) ModuleErrorf(logicModule Module, format string, 121 args ...interface{}) { 122 123 s.error(s.context.ModuleErrorf(logicModule, format, args...)) 124} 125 126func (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 131func (s *singletonContext) Failed() bool { 132 return len(s.errs) > 0 133} 134 135func (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 146func (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 161func (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 172func (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 188func (s *singletonContext) RequireNinjaVersion(major, minor, micro int) { 189 s.context.requireNinjaVersion(major, minor, micro) 190} 191 192func (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 203func (s *singletonContext) VisitAllModules(visit func(Module)) { 204 s.context.VisitAllModules(visit) 205} 206 207func (s *singletonContext) VisitAllModulesIf(pred func(Module) bool, 208 visit func(Module)) { 209 210 s.context.VisitAllModulesIf(pred, visit) 211} 212 213func (s *singletonContext) VisitDepsDepthFirst(module Module, 214 visit func(Module)) { 215 216 s.context.VisitDepsDepthFirst(module, visit) 217} 218 219func (s *singletonContext) VisitDepsDepthFirstIf(module Module, 220 pred func(Module) bool, visit func(Module)) { 221 222 s.context.VisitDepsDepthFirstIf(module, pred, visit) 223} 224 225func (s *singletonContext) PrimaryModule(module Module) Module { 226 return s.context.PrimaryModule(module) 227} 228 229func (s *singletonContext) FinalModule(module Module) Module { 230 return s.context.FinalModule(module) 231} 232 233func (s *singletonContext) VisitAllModuleVariants(module Module, visit func(Module)) { 234 s.context.VisitAllModuleVariants(module, visit) 235} 236 237func (s *singletonContext) AddNinjaFileDeps(deps ...string) { 238 s.ninjaFileDeps = append(s.ninjaFileDeps, deps...) 239} 240 241func (s *singletonContext) GlobWithDeps(pattern string, 242 excludes []string) ([]string, error) { 243 return s.context.glob(pattern, excludes) 244} 245 246func (s *singletonContext) Fs() pathtools.FileSystem { 247 return s.context.fs 248} 249