1// Copyright 2015 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 android 16 17import ( 18 "fmt" 19 "strings" 20 21 "github.com/google/blueprint" 22) 23 24// PackageContext is a wrapper for blueprint.PackageContext that adds 25// some android-specific helper functions. 26type PackageContext struct { 27 blueprint.PackageContext 28} 29 30func NewPackageContext(pkgPath string) PackageContext { 31 return PackageContext{blueprint.NewPackageContext(pkgPath)} 32} 33 34// configErrorWrapper can be used with Path functions when a Context is not 35// available. A Config can be provided, and errors are stored as a list for 36// later retrieval. 37// 38// The most common use here will be with VariableFunc, where only a config is 39// provided, and an error should be returned. 40type configErrorWrapper struct { 41 pctx PackageContext 42 config Config 43 errors []error 44} 45 46var _ PathContext = &configErrorWrapper{} 47var _ errorfContext = &configErrorWrapper{} 48var _ PackageVarContext = &configErrorWrapper{} 49var _ PackagePoolContext = &configErrorWrapper{} 50var _ PackageRuleContext = &configErrorWrapper{} 51 52func (e *configErrorWrapper) Config() Config { 53 return e.config 54} 55func (e *configErrorWrapper) Errorf(format string, args ...interface{}) { 56 e.errors = append(e.errors, fmt.Errorf(format, args...)) 57} 58func (e *configErrorWrapper) AddNinjaFileDeps(deps ...string) { 59 e.pctx.AddNinjaFileDeps(deps...) 60} 61 62type PackageVarContext interface { 63 PathContext 64 errorfContext 65} 66 67type PackagePoolContext PackageVarContext 68type PackageRuleContext PackageVarContext 69 70// VariableFunc wraps blueprint.PackageContext.VariableFunc, converting the interface{} config 71// argument to a PackageVarContext. 72func (p PackageContext) VariableFunc(name string, 73 f func(PackageVarContext) string) blueprint.Variable { 74 75 return p.PackageContext.VariableFunc(name, func(config interface{}) (string, error) { 76 ctx := &configErrorWrapper{p, config.(Config), nil} 77 ret := f(ctx) 78 if len(ctx.errors) > 0 { 79 return "", ctx.errors[0] 80 } 81 return ret, nil 82 }) 83} 84 85// PoolFunc wraps blueprint.PackageContext.PoolFunc, converting the interface{} config 86// argument to a Context that supports Config(). 87func (p PackageContext) PoolFunc(name string, 88 f func(PackagePoolContext) blueprint.PoolParams) blueprint.Pool { 89 90 return p.PackageContext.PoolFunc(name, func(config interface{}) (blueprint.PoolParams, error) { 91 ctx := &configErrorWrapper{p, config.(Config), nil} 92 params := f(ctx) 93 if len(ctx.errors) > 0 { 94 return params, ctx.errors[0] 95 } 96 return params, nil 97 }) 98} 99 100// RuleFunc wraps blueprint.PackageContext.RuleFunc, converting the interface{} config 101// argument to a Context that supports Config(), and provides a default Pool if none is 102// specified. 103func (p PackageContext) RuleFunc(name string, 104 f func(PackageRuleContext) blueprint.RuleParams, argNames ...string) blueprint.Rule { 105 106 return p.PackageContext.RuleFunc(name, func(config interface{}) (blueprint.RuleParams, error) { 107 ctx := &configErrorWrapper{p, config.(Config), nil} 108 params := f(ctx) 109 if len(ctx.errors) > 0 { 110 return params, ctx.errors[0] 111 } 112 if ctx.Config().UseRemoteBuild() && params.Pool == nil { 113 // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by 114 // goma/RBE, restrict jobs to the local parallelism value 115 params.Pool = localPool 116 } 117 return params, nil 118 }, argNames...) 119} 120 121// SourcePathVariable returns a Variable whose value is the source directory 122// appended with the supplied path. It may only be called during a Go package's 123// initialization - either from the init() function or as part of a 124// package-scoped variable's initialization. 125func (p PackageContext) SourcePathVariable(name, path string) blueprint.Variable { 126 return p.VariableFunc(name, func(ctx PackageVarContext) string { 127 p, err := safePathForSource(ctx, path) 128 if err != nil { 129 ctx.Errorf("%s", err.Error()) 130 } 131 return p.String() 132 }) 133} 134 135// SourcePathsVariable returns a Variable whose value is the source directory 136// appended with the supplied paths, joined with separator. It may only be 137// called during a Go package's initialization - either from the init() 138// function or as part of a package-scoped variable's initialization. 139func (p PackageContext) SourcePathsVariable(name, separator string, paths ...string) blueprint.Variable { 140 return p.VariableFunc(name, func(ctx PackageVarContext) string { 141 var ret []string 142 for _, path := range paths { 143 p, err := safePathForSource(ctx, path) 144 if err != nil { 145 ctx.Errorf("%s", err.Error()) 146 } 147 ret = append(ret, p.String()) 148 } 149 return strings.Join(ret, separator) 150 }) 151} 152 153// SourcePathVariableWithEnvOverride returns a Variable whose value is the source directory 154// appended with the supplied path, or the value of the given environment variable if it is set. 155// The environment variable is not required to point to a path inside the source tree. 156// It may only be called during a Go package's initialization - either from the init() function or 157// as part of a package-scoped variable's initialization. 158func (p PackageContext) SourcePathVariableWithEnvOverride(name, path, env string) blueprint.Variable { 159 return p.VariableFunc(name, func(ctx PackageVarContext) string { 160 p, err := safePathForSource(ctx, path) 161 if err != nil { 162 ctx.Errorf("%s", err.Error()) 163 } 164 return ctx.Config().GetenvWithDefault(env, p.String()) 165 }) 166} 167 168// HostBinToolVariable returns a Variable whose value is the path to a host tool 169// in the bin directory for host targets. It may only be called during a Go 170// package's initialization - either from the init() function or as part of a 171// package-scoped variable's initialization. 172func (p PackageContext) HostBinToolVariable(name, path string) blueprint.Variable { 173 return p.VariableFunc(name, func(ctx PackageVarContext) string { 174 return ctx.Config().HostToolPath(ctx, path).String() 175 }) 176} 177 178// HostJNIToolVariable returns a Variable whose value is the path to a host tool 179// in the lib directory for host targets. It may only be called during a Go 180// package's initialization - either from the init() function or as part of a 181// package-scoped variable's initialization. 182func (p PackageContext) HostJNIToolVariable(name, path string) blueprint.Variable { 183 return p.VariableFunc(name, func(ctx PackageVarContext) string { 184 return ctx.Config().HostJNIToolPath(ctx, path).String() 185 }) 186} 187 188// HostJavaToolVariable returns a Variable whose value is the path to a host 189// tool in the frameworks directory for host targets. It may only be called 190// during a Go package's initialization - either from the init() function or as 191// part of a package-scoped variable's initialization. 192func (p PackageContext) HostJavaToolVariable(name, path string) blueprint.Variable { 193 return p.VariableFunc(name, func(ctx PackageVarContext) string { 194 return ctx.Config().HostJavaToolPath(ctx, path).String() 195 }) 196} 197 198// IntermediatesPathVariable returns a Variable whose value is the intermediate 199// directory appended with the supplied path. It may only be called during a Go 200// package's initialization - either from the init() function or as part of a 201// package-scoped variable's initialization. 202func (p PackageContext) IntermediatesPathVariable(name, path string) blueprint.Variable { 203 return p.VariableFunc(name, func(ctx PackageVarContext) string { 204 return PathForIntermediates(ctx, path).String() 205 }) 206} 207 208// PrefixedExistentPathsForSourcesVariable returns a Variable whose value is the 209// list of present source paths prefixed with the supplied prefix. It may only 210// be called during a Go package's initialization - either from the init() 211// function or as part of a package-scoped variable's initialization. 212func (p PackageContext) PrefixedExistentPathsForSourcesVariable( 213 name, prefix string, paths []string) blueprint.Variable { 214 215 return p.VariableFunc(name, func(ctx PackageVarContext) string { 216 paths := ExistentPathsForSources(ctx, paths) 217 return JoinWithPrefix(paths.Strings(), prefix) 218 }) 219} 220 221// AndroidStaticRule is an alias for StaticRule. 222func (p PackageContext) AndroidStaticRule(name string, params blueprint.RuleParams, 223 argNames ...string) blueprint.Rule { 224 return p.StaticRule(name, params, argNames...) 225} 226 227// StaticRule wraps blueprint.StaticRule and provides a default Pool if none is specified. 228func (p PackageContext) StaticRule(name string, params blueprint.RuleParams, 229 argNames ...string) blueprint.Rule { 230 return p.RuleFunc(name, func(PackageRuleContext) blueprint.RuleParams { 231 return params 232 }, argNames...) 233} 234 235// RemoteRuleSupports configures rules with whether they have Goma and/or RBE support. 236type RemoteRuleSupports struct { 237 Goma bool 238 RBE bool 239} 240 241// AndroidRemoteStaticRule wraps blueprint.StaticRule but uses goma or RBE's parallelism if goma or RBE are enabled 242// and the appropriate SUPPORTS_* flag is set. 243func (p PackageContext) AndroidRemoteStaticRule(name string, supports RemoteRuleSupports, params blueprint.RuleParams, 244 argNames ...string) blueprint.Rule { 245 246 return p.PackageContext.RuleFunc(name, func(config interface{}) (blueprint.RuleParams, error) { 247 ctx := &configErrorWrapper{p, config.(Config), nil} 248 if ctx.Config().UseGoma() && !supports.Goma { 249 // When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the 250 // local parallelism value 251 params.Pool = localPool 252 } 253 254 if ctx.Config().UseRBE() && !supports.RBE { 255 // When USE_RBE=true is set and the rule is not supported by RBE, restrict jobs to the 256 // local parallelism value 257 params.Pool = localPool 258 } 259 260 return params, nil 261 }, argNames...) 262} 263