blob: c19debbb4442fb81f0aec91c28a1011bb0a6cc5d [file] [log] [blame]
Dan Willemsen34cc69e2015-09-23 15:26:20 -07001// 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
Colin Cross635c3b02016-05-18 15:37:25 -070015package android
Dan Willemsen34cc69e2015-09-23 15:26:20 -070016
17import (
18 "fmt"
Colin Crossc6bbef32017-08-14 14:16:06 -070019 "strings"
Dan Willemsen34cc69e2015-09-23 15:26:20 -070020
21 "github.com/google/blueprint"
Colin Cross77cdcfd2021-03-12 11:28:25 -080022
23 "android/soong/remoteexec"
Dan Willemsen34cc69e2015-09-23 15:26:20 -070024)
25
Colin Cross0875c522017-11-28 17:34:01 -080026// PackageContext is a wrapper for blueprint.PackageContext that adds
Dan Willemsen34cc69e2015-09-23 15:26:20 -070027// some android-specific helper functions.
Colin Cross0875c522017-11-28 17:34:01 -080028type PackageContext struct {
Dan Willemsen34cc69e2015-09-23 15:26:20 -070029 blueprint.PackageContext
30}
31
Colin Cross0875c522017-11-28 17:34:01 -080032func NewPackageContext(pkgPath string) PackageContext {
33 return PackageContext{blueprint.NewPackageContext(pkgPath)}
Dan Willemsen34cc69e2015-09-23 15:26:20 -070034}
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 {
Colin Cross0875c522017-11-28 17:34:01 -080043 pctx PackageContext
Dan Willemsen34cc69e2015-09-23 15:26:20 -070044 config Config
45 errors []error
46}
47
48var _ PathContext = &configErrorWrapper{}
49var _ errorfContext = &configErrorWrapper{}
Dan Willemsen54daaf02018-03-12 13:24:09 -070050var _ PackageVarContext = &configErrorWrapper{}
51var _ PackagePoolContext = &configErrorWrapper{}
52var _ PackageRuleContext = &configErrorWrapper{}
Dan Willemsen34cc69e2015-09-23 15:26:20 -070053
Colin Crossaabf6792017-11-29 00:27:14 -080054func (e *configErrorWrapper) Config() Config {
Dan Willemsen34cc69e2015-09-23 15:26:20 -070055 return e.config
56}
57func (e *configErrorWrapper) Errorf(format string, args ...interface{}) {
58 e.errors = append(e.errors, fmt.Errorf(format, args...))
59}
Dan Willemsen7b310ee2015-12-18 15:11:17 -080060func (e *configErrorWrapper) AddNinjaFileDeps(deps ...string) {
Colin Cross12129292020-10-29 18:23:58 -070061 e.config.addNinjaFileDeps(deps...)
Dan Willemsen7b310ee2015-12-18 15:11:17 -080062}
Dan Willemsen34cc69e2015-09-23 15:26:20 -070063
Dan Willemsen54daaf02018-03-12 13:24:09 -070064type PackageVarContext interface {
65 PathContext
66 errorfContext
67}
68
69type PackagePoolContext PackageVarContext
70type PackageRuleContext PackageVarContext
71
Colin Cross0875c522017-11-28 17:34:01 -080072// VariableFunc wraps blueprint.PackageContext.VariableFunc, converting the interface{} config
Dan Willemsen54daaf02018-03-12 13:24:09 -070073// argument to a PackageVarContext.
Colin Cross0875c522017-11-28 17:34:01 -080074func (p PackageContext) VariableFunc(name string,
Dan Willemsen54daaf02018-03-12 13:24:09 -070075 f func(PackageVarContext) string) blueprint.Variable {
Colin Cross0875c522017-11-28 17:34:01 -080076
77 return p.PackageContext.VariableFunc(name, func(config interface{}) (string, error) {
Dan Willemsen54daaf02018-03-12 13:24:09 -070078 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
Colin Cross0875c522017-11-28 17:34:01 -080084 })
85}
86
87// PoolFunc wraps blueprint.PackageContext.PoolFunc, converting the interface{} config
Dan Willemsen54daaf02018-03-12 13:24:09 -070088// argument to a Context that supports Config().
Colin Cross0875c522017-11-28 17:34:01 -080089func (p PackageContext) PoolFunc(name string,
Dan Willemsen54daaf02018-03-12 13:24:09 -070090 f func(PackagePoolContext) blueprint.PoolParams) blueprint.Pool {
Colin Cross0875c522017-11-28 17:34:01 -080091
92 return p.PackageContext.PoolFunc(name, func(config interface{}) (blueprint.PoolParams, error) {
Dan Willemsen54daaf02018-03-12 13:24:09 -070093 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
Colin Cross0875c522017-11-28 17:34:01 -080099 })
100}
101
102// RuleFunc wraps blueprint.PackageContext.RuleFunc, converting the interface{} config
Colin Cross2e2dbc22019-09-25 13:31:46 -0700103// argument to a Context that supports Config(), and provides a default Pool if none is
104// specified.
Colin Cross0875c522017-11-28 17:34:01 -0800105func (p PackageContext) RuleFunc(name string,
Dan Willemsen54daaf02018-03-12 13:24:09 -0700106 f func(PackageRuleContext) blueprint.RuleParams, argNames ...string) blueprint.Rule {
Colin Cross0875c522017-11-28 17:34:01 -0800107
108 return p.PackageContext.RuleFunc(name, func(config interface{}) (blueprint.RuleParams, error) {
Dan Willemsen54daaf02018-03-12 13:24:09 -0700109 ctx := &configErrorWrapper{p, config.(Config), nil}
110 params := f(ctx)
111 if len(ctx.errors) > 0 {
112 return params, ctx.errors[0]
113 }
Colin Cross8b8bec32019-11-15 13:18:43 -0800114 if ctx.Config().UseRemoteBuild() && params.Pool == nil {
Ramy Medhatdd0418a2019-11-04 18:16:11 -0500115 // 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
Colin Cross2e2dbc22019-09-25 13:31:46 -0700117 params.Pool = localPool
118 }
Dan Willemsen54daaf02018-03-12 13:24:09 -0700119 return params, nil
Colin Cross0875c522017-11-28 17:34:01 -0800120 }, argNames...)
121}
122
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700123// 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.
Colin Cross0875c522017-11-28 17:34:01 -0800127func (p PackageContext) SourcePathVariable(name, path string) blueprint.Variable {
Dan Willemsen54daaf02018-03-12 13:24:09 -0700128 return p.VariableFunc(name, func(ctx PackageVarContext) string {
Colin Crossfe4bc362018-09-12 10:02:13 -0700129 p, err := safePathForSource(ctx, path)
130 if err != nil {
131 ctx.Errorf("%s", err.Error())
132 }
133 return p.String()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700134 })
135}
136
Colin Crossc6bbef32017-08-14 14:16:06 -0700137// 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.
Colin Cross0875c522017-11-28 17:34:01 -0800141func (p PackageContext) SourcePathsVariable(name, separator string, paths ...string) blueprint.Variable {
Dan Willemsen54daaf02018-03-12 13:24:09 -0700142 return p.VariableFunc(name, func(ctx PackageVarContext) string {
Colin Crossc6bbef32017-08-14 14:16:06 -0700143 var ret []string
144 for _, path := range paths {
Colin Crossfe4bc362018-09-12 10:02:13 -0700145 p, err := safePathForSource(ctx, path)
146 if err != nil {
147 ctx.Errorf("%s", err.Error())
148 }
Colin Crossc6bbef32017-08-14 14:16:06 -0700149 ret = append(ret, p.String())
150 }
Dan Willemsen54daaf02018-03-12 13:24:09 -0700151 return strings.Join(ret, separator)
Colin Crossc6bbef32017-08-14 14:16:06 -0700152 })
153}
154
Colin Cross64162712017-08-08 13:17:59 -0700155// 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.
Colin Cross0875c522017-11-28 17:34:01 -0800160func (p PackageContext) SourcePathVariableWithEnvOverride(name, path, env string) blueprint.Variable {
Dan Willemsen54daaf02018-03-12 13:24:09 -0700161 return p.VariableFunc(name, func(ctx PackageVarContext) string {
Colin Crossfe4bc362018-09-12 10:02:13 -0700162 p, err := safePathForSource(ctx, path)
163 if err != nil {
164 ctx.Errorf("%s", err.Error())
165 }
Dan Willemsen54daaf02018-03-12 13:24:09 -0700166 return ctx.Config().GetenvWithDefault(env, p.String())
Colin Cross64162712017-08-08 13:17:59 -0700167 })
168}
169
Colin Cross5ab4e6d2017-11-22 16:20:45 -0800170// HostBinToolVariable returns a Variable whose value is the path to a host tool
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700171// 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.
Colin Cross0875c522017-11-28 17:34:01 -0800174func (p PackageContext) HostBinToolVariable(name, path string) blueprint.Variable {
Dan Willemsen54daaf02018-03-12 13:24:09 -0700175 return p.VariableFunc(name, func(ctx PackageVarContext) string {
Martin Stjernholm7260d062019-12-09 21:47:14 +0000176 return ctx.Config().HostToolPath(ctx, path).String()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700177 })
178}
179
Colin Cross5ab4e6d2017-11-22 16:20:45 -0800180// 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 {
Dan Willemsen54daaf02018-03-12 13:24:09 -0700185 return p.VariableFunc(name, func(ctx PackageVarContext) string {
Martin Stjernholm7260d062019-12-09 21:47:14 +0000186 return ctx.Config().HostJNIToolPath(ctx, path).String()
Colin Cross5ab4e6d2017-11-22 16:20:45 -0800187 })
188}
189
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700190// 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.
Colin Cross0875c522017-11-28 17:34:01 -0800194func (p PackageContext) HostJavaToolVariable(name, path string) blueprint.Variable {
Dan Willemsen54daaf02018-03-12 13:24:09 -0700195 return p.VariableFunc(name, func(ctx PackageVarContext) string {
Martin Stjernholm7260d062019-12-09 21:47:14 +0000196 return ctx.Config().HostJavaToolPath(ctx, path).String()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700197 })
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.
Colin Cross0875c522017-11-28 17:34:01 -0800204func (p PackageContext) IntermediatesPathVariable(name, path string) blueprint.Variable {
Dan Willemsen54daaf02018-03-12 13:24:09 -0700205 return p.VariableFunc(name, func(ctx PackageVarContext) string {
206 return PathForIntermediates(ctx, path).String()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700207 })
208}
209
Jeff Gaston734e3802017-04-10 15:47:24 -0700210// PrefixedExistentPathsForSourcesVariable returns a Variable whose value is the
Dan Willemsen7b310ee2015-12-18 15:11:17 -0800211// 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()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700213// function or as part of a package-scoped variable's initialization.
Colin Cross0875c522017-11-28 17:34:01 -0800214func (p PackageContext) PrefixedExistentPathsForSourcesVariable(
Dan Willemsen7b310ee2015-12-18 15:11:17 -0800215 name, prefix string, paths []string) blueprint.Variable {
216
Dan Willemsen54daaf02018-03-12 13:24:09 -0700217 return p.VariableFunc(name, func(ctx PackageVarContext) string {
Colin Cross32f38982018-02-22 11:47:25 -0800218 paths := ExistentPathsForSources(ctx, paths)
Dan Willemsen54daaf02018-03-12 13:24:09 -0700219 return JoinWithPrefix(paths.Strings(), prefix)
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700220 })
221}
Colin Cross9d45bb72016-08-29 16:14:13 -0700222
Colin Cross2e2dbc22019-09-25 13:31:46 -0700223// AndroidStaticRule is an alias for StaticRule.
Colin Cross0875c522017-11-28 17:34:01 -0800224func (p PackageContext) AndroidStaticRule(name string, params blueprint.RuleParams,
Colin Cross9d45bb72016-08-29 16:14:13 -0700225 argNames ...string) blueprint.Rule {
Colin Cross2e2dbc22019-09-25 13:31:46 -0700226 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 {
Dan Willemsen54daaf02018-03-12 13:24:09 -0700233 return params
Colin Cross9d45bb72016-08-29 16:14:13 -0700234 }, argNames...)
235}
236
Ramy Medhat8ea054a2020-01-27 14:19:44 -0500237// RemoteRuleSupports configures rules with whether they have Goma and/or RBE support.
238type RemoteRuleSupports struct {
Ramy Medhat1dcc27e2020-04-21 21:36:23 -0400239 Goma bool
240 RBE bool
Ramy Medhat8ea054a2020-01-27 14:19:44 -0500241}
242
Ramy Medhatdd0418a2019-11-04 18:16:11 -0500243// 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,
Colin Cross9d45bb72016-08-29 16:14:13 -0700246 argNames ...string) blueprint.Rule {
Ramy Medhatdd0418a2019-11-04 18:16:11 -0500247
248 return p.PackageContext.RuleFunc(name, func(config interface{}) (blueprint.RuleParams, error) {
249 ctx := &configErrorWrapper{p, config.(Config), nil}
Ramy Medhat8ea054a2020-01-27 14:19:44 -0500250 if ctx.Config().UseGoma() && !supports.Goma {
Ramy Medhatdd0418a2019-11-04 18:16:11 -0500251 // 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
Ramy Medhat8ea054a2020-01-27 14:19:44 -0500256 if ctx.Config().UseRBE() && !supports.RBE {
Ramy Medhatdd0418a2019-11-04 18:16:11 -0500257 // 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...)
Colin Cross9d45bb72016-08-29 16:14:13 -0700264}
Colin Cross77cdcfd2021-03-12 11:28:25 -0800265
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}