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