• 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
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