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