package_ctx.go 13 KB

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