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