blob: f353a9dc80bc59ee77f44e10495c436467bb5591 [file] [log] [blame]
Liz Kammer620dea62021-04-14 17:36:10 -04001// 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 (
Liz Kammer620dea62021-04-14 17:36:10 -040018 "fmt"
19 "path/filepath"
20 "strings"
21
Chris Parsons953b3562021-09-20 15:14:39 -040022 "android/soong/bazel"
23
Liz Kammer620dea62021-04-14 17:36:10 -040024 "github.com/google/blueprint"
25 "github.com/google/blueprint/pathtools"
26)
27
28// bazel_paths contains methods to:
29// * resolve Soong path and module references into bazel.LabelList
30// * resolve Bazel path references into Soong-compatible paths
31//
32// There is often a similar method for Bazel as there is for Soong path handling and should be used
33// in similar circumstances
34//
35// Bazel Soong
36//
37// BazelLabelForModuleSrc PathForModuleSrc
38// BazelLabelForModuleSrcExcludes PathForModuleSrcExcludes
39// BazelLabelForModuleDeps n/a
40// tbd PathForSource
41// tbd ExistentPathsForSources
42// PathForBazelOut PathForModuleOut
43//
44// Use cases:
45// * Module contains a property (often tagged `android:"path"`) that expects paths *relative to the
46// module directory*:
47// * BazelLabelForModuleSrcExcludes, if the module also contains an excludes_<propname> property
48// * BazelLabelForModuleSrc, otherwise
49// * Converting references to other modules to Bazel Labels:
50// BazelLabelForModuleDeps
51// * Converting a path obtained from bazel_handler cquery results:
52// PathForBazelOut
53//
54// NOTE: all Soong globs are expanded within Soong rather than being converted to a Bazel glob
55// syntax. This occurs because Soong does not have a concept of crossing package boundaries,
56// so the glob as computed by Soong may contain paths that cross package-boundaries. These
57// would be unknowingly omitted if the glob were handled by Bazel. By expanding globs within
58// Soong, we support identification and detection (within Bazel) use of paths that cross
59// package boundaries.
60//
61// Path resolution:
62// * filepath/globs: resolves as itself or is converted to an absolute Bazel label (e.g.
63// //path/to/dir:<filepath>) if path exists in a separate package or subpackage.
64// * references to other modules (using the ":name{.tag}" syntax). These resolve as a Bazel label
65// for a target. If the Bazel target is in the local module directory, it will be returned
66// relative to the current package (e.g. ":<target>"). Otherwise, it will be returned as an
67// absolute Bazel label (e.g. "//path/to/dir:<target>"). If the reference to another module
68// cannot be resolved,the function will panic. This is often due to the dependency not being added
69// via an AddDependency* method.
70
Jingwen Chen55bc8202021-11-02 06:40:51 +000071// A minimal context interface to check if a module should be converted by bp2build,
72// with functions containing information to match against allowlists and denylists.
73// If a module is deemed to be convertible by bp2build, then it should rely on a
74// BazelConversionPathContext for more functions for dep/path features.
75type BazelConversionContext interface {
76 Config() Config
Liz Kammer620dea62021-04-14 17:36:10 -040077
Liz Kammer620dea62021-04-14 17:36:10 -040078 Module() Module
Liz Kammer6eff3232021-08-26 08:37:59 -040079 OtherModuleType(m blueprint.Module) string
Liz Kammer620dea62021-04-14 17:36:10 -040080 OtherModuleName(m blueprint.Module) string
81 OtherModuleDir(m blueprint.Module) string
Jingwen Chen55bc8202021-11-02 06:40:51 +000082}
83
84// A subset of the ModuleContext methods which are sufficient to resolve references to paths/deps in
85// order to form a Bazel-compatible label for conversion.
86type BazelConversionPathContext interface {
87 EarlyModulePathContext
88 BazelConversionContext
89
90 ModuleErrorf(fmt string, args ...interface{})
91 PropertyErrorf(property, fmt string, args ...interface{})
92 GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
93 ModuleFromName(name string) (blueprint.Module, bool)
Liz Kammer6eff3232021-08-26 08:37:59 -040094 AddUnconvertedBp2buildDep(string)
Liz Kammerdaa09ef2021-12-15 15:35:38 -050095 AddMissingBp2buildDep(dep string)
Liz Kammer620dea62021-04-14 17:36:10 -040096}
97
98// BazelLabelForModuleDeps expects a list of reference to other modules, ("<module>"
99// or ":<module>") and returns a Bazel-compatible label which corresponds to dependencies on the
100// module within the given ctx.
Jingwen Chen55bc8202021-11-02 06:40:51 +0000101func BazelLabelForModuleDeps(ctx BazelConversionPathContext, modules []string) bazel.LabelList {
Chris Parsons953b3562021-09-20 15:14:39 -0400102 return BazelLabelForModuleDepsWithFn(ctx, modules, BazelModuleLabel)
Liz Kammer2d7bbe32021-06-10 18:20:06 -0400103}
104
105// BazelLabelForModuleWholeDepsExcludes expects two lists: modules (containing modules to include in
106// the list), and excludes (modules to exclude from the list). Both of these should contain
107// references to other modules, ("<module>" or ":<module>"). It returns a Bazel-compatible label
108// list which corresponds to dependencies on the module within the given ctx, and the excluded
109// dependencies. Prebuilt dependencies will be appended with _alwayslink so they can be handled as
110// whole static libraries.
Jingwen Chen55bc8202021-11-02 06:40:51 +0000111func BazelLabelForModuleDepsExcludes(ctx BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
Chris Parsons953b3562021-09-20 15:14:39 -0400112 return BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, BazelModuleLabel)
Liz Kammer2d7bbe32021-06-10 18:20:06 -0400113}
114
Chris Parsons953b3562021-09-20 15:14:39 -0400115// BazelLabelForModuleDepsWithFn expects a list of reference to other modules, ("<module>"
116// or ":<module>") and applies moduleToLabelFn to determine and return a Bazel-compatible label
117// which corresponds to dependencies on the module within the given ctx.
Jingwen Chen55bc8202021-11-02 06:40:51 +0000118func BazelLabelForModuleDepsWithFn(ctx BazelConversionPathContext, modules []string,
119 moduleToLabelFn func(BazelConversionPathContext, blueprint.Module) string) bazel.LabelList {
Liz Kammer620dea62021-04-14 17:36:10 -0400120 var labels bazel.LabelList
Chris Parsons51f8c392021-08-03 21:01:05 -0400121 // In some cases, a nil string list is different than an explicitly empty list.
122 if len(modules) == 0 && modules != nil {
123 labels.Includes = []bazel.Label{}
124 return labels
125 }
Liz Kammer620dea62021-04-14 17:36:10 -0400126 for _, module := range modules {
127 bpText := module
128 if m := SrcIsModule(module); m == "" {
129 module = ":" + module
130 }
131 if m, t := SrcIsModuleWithTag(module); m != "" {
Chris Parsons953b3562021-09-20 15:14:39 -0400132 l := getOtherModuleLabel(ctx, m, t, moduleToLabelFn)
Liz Kammerdaa09ef2021-12-15 15:35:38 -0500133 if l != nil {
134 l.OriginalModuleName = bpText
135 labels.Includes = append(labels.Includes, *l)
136 }
Liz Kammer620dea62021-04-14 17:36:10 -0400137 } else {
138 ctx.ModuleErrorf("%q, is not a module reference", module)
139 }
140 }
141 return labels
142}
143
Chris Parsons953b3562021-09-20 15:14:39 -0400144// BazelLabelForModuleDepsExcludesWithFn expects two lists: modules (containing modules to include in the
145// list), and excludes (modules to exclude from the list). Both of these should contain references
146// to other modules, ("<module>" or ":<module>"). It applies moduleToLabelFn to determine and return a
147// Bazel-compatible label list which corresponds to dependencies on the module within the given ctx, and
148// the excluded dependencies.
Jingwen Chen55bc8202021-11-02 06:40:51 +0000149func BazelLabelForModuleDepsExcludesWithFn(ctx BazelConversionPathContext, modules, excludes []string,
150 moduleToLabelFn func(BazelConversionPathContext, blueprint.Module) string) bazel.LabelList {
Chris Parsons953b3562021-09-20 15:14:39 -0400151 moduleLabels := BazelLabelForModuleDepsWithFn(ctx, RemoveListFromList(modules, excludes), moduleToLabelFn)
Liz Kammer47535c52021-06-02 16:02:22 -0400152 if len(excludes) == 0 {
153 return moduleLabels
154 }
Chris Parsons953b3562021-09-20 15:14:39 -0400155 excludeLabels := BazelLabelForModuleDepsWithFn(ctx, excludes, moduleToLabelFn)
Liz Kammer47535c52021-06-02 16:02:22 -0400156 return bazel.LabelList{
157 Includes: moduleLabels.Includes,
158 Excludes: excludeLabels.Includes,
159 }
160}
161
Jingwen Chen55bc8202021-11-02 06:40:51 +0000162func BazelLabelForModuleSrcSingle(ctx BazelConversionPathContext, path string) bazel.Label {
Liz Kammerdaa09ef2021-12-15 15:35:38 -0500163 if srcs := BazelLabelForModuleSrcExcludes(ctx, []string{path}, []string(nil)).Includes; len(srcs) > 0 {
164 return srcs[0]
165 }
166 return bazel.Label{}
Lukacs T. Berki1353e592021-04-30 15:35:09 +0200167}
168
Jingwen Chen55bc8202021-11-02 06:40:51 +0000169func BazelLabelForModuleDepSingle(ctx BazelConversionPathContext, path string) bazel.Label {
Liz Kammerdaa09ef2021-12-15 15:35:38 -0500170 if srcs := BazelLabelForModuleDepsExcludes(ctx, []string{path}, []string(nil)).Includes; len(srcs) > 0 {
171 return srcs[0]
172 }
173 return bazel.Label{}
Rupert Shuttleworth6e4950a2021-07-27 01:34:59 -0400174}
175
Liz Kammer620dea62021-04-14 17:36:10 -0400176// BazelLabelForModuleSrc expects a list of path (relative to local module directory) and module
177// references (":<module>") and returns a bazel.LabelList{} containing the resolved references in
178// paths, relative to the local module, or Bazel-labels (absolute if in a different package or
179// relative if within the same package).
180// Properties must have been annotated with struct tag `android:"path"` so that dependencies modules
181// will have already been handled by the path_deps mutator.
Jingwen Chen55bc8202021-11-02 06:40:51 +0000182func BazelLabelForModuleSrc(ctx BazelConversionPathContext, paths []string) bazel.LabelList {
Liz Kammer620dea62021-04-14 17:36:10 -0400183 return BazelLabelForModuleSrcExcludes(ctx, paths, []string(nil))
184}
185
186// BazelLabelForModuleSrc expects lists of path and excludes (relative to local module directory)
187// and module references (":<module>") and returns a bazel.LabelList{} containing the resolved
188// references in paths, minus those in excludes, relative to the local module, or Bazel-labels
189// (absolute if in a different package or relative if within the same package).
190// Properties must have been annotated with struct tag `android:"path"` so that dependencies modules
191// will have already been handled by the path_deps mutator.
Jingwen Chen55bc8202021-11-02 06:40:51 +0000192func BazelLabelForModuleSrcExcludes(ctx BazelConversionPathContext, paths, excludes []string) bazel.LabelList {
Liz Kammer620dea62021-04-14 17:36:10 -0400193 excludeLabels := expandSrcsForBazel(ctx, excludes, []string(nil))
194 excluded := make([]string, 0, len(excludeLabels.Includes))
195 for _, e := range excludeLabels.Includes {
196 excluded = append(excluded, e.Label)
197 }
198 labels := expandSrcsForBazel(ctx, paths, excluded)
199 labels.Excludes = excludeLabels.Includes
200 labels = transformSubpackagePaths(ctx, labels)
201 return labels
202}
203
204// Returns true if a prefix + components[:i] + /Android.bp exists
205// TODO(b/185358476) Could check for BUILD file instead of checking for Android.bp file, or ensure BUILD is always generated?
206func directoryHasBlueprint(fs pathtools.FileSystem, prefix string, components []string, componentIndex int) bool {
207 blueprintPath := prefix
208 if blueprintPath != "" {
209 blueprintPath = blueprintPath + "/"
210 }
211 blueprintPath = blueprintPath + strings.Join(components[:componentIndex+1], "/")
212 blueprintPath = blueprintPath + "/Android.bp"
213 if exists, _, _ := fs.Exists(blueprintPath); exists {
214 return true
215 } else {
216 return false
217 }
218}
219
220// Transform a path (if necessary) to acknowledge package boundaries
221//
222// e.g. something like
223// async_safe/include/async_safe/CHECK.h
224// might become
225// //bionic/libc/async_safe:include/async_safe/CHECK.h
226// if the "async_safe" directory is actually a package and not just a directory.
227//
228// In particular, paths that extend into packages are transformed into absolute labels beginning with //.
229func transformSubpackagePath(ctx BazelConversionPathContext, path bazel.Label) bazel.Label {
230 var newPath bazel.Label
231
Jingwen Chen38e62642021-04-19 05:00:15 +0000232 // Don't transform OriginalModuleName
233 newPath.OriginalModuleName = path.OriginalModuleName
Liz Kammer620dea62021-04-14 17:36:10 -0400234
235 if strings.HasPrefix(path.Label, "//") {
236 // Assume absolute labels are already correct (e.g. //path/to/some/package:foo.h)
237 newPath.Label = path.Label
238 return newPath
239 }
240
241 newLabel := ""
242 pathComponents := strings.Split(path.Label, "/")
243 foundBlueprint := false
244 // Check the deepest subdirectory first and work upwards
245 for i := len(pathComponents) - 1; i >= 0; i-- {
246 pathComponent := pathComponents[i]
247 var sep string
248 if !foundBlueprint && directoryHasBlueprint(ctx.Config().fs, ctx.ModuleDir(), pathComponents, i) {
249 sep = ":"
250 foundBlueprint = true
251 } else {
252 sep = "/"
253 }
254 if newLabel == "" {
255 newLabel = pathComponent
256 } else {
257 newLabel = pathComponent + sep + newLabel
258 }
259 }
260 if foundBlueprint {
261 // Ensure paths end up looking like //bionic/... instead of //./bionic/...
262 moduleDir := ctx.ModuleDir()
263 if strings.HasPrefix(moduleDir, ".") {
264 moduleDir = moduleDir[1:]
265 }
266 // Make the path into an absolute label (e.g. //bionic/libc/foo:bar.h instead of just foo:bar.h)
267 if moduleDir == "" {
268 newLabel = "//" + newLabel
269 } else {
270 newLabel = "//" + moduleDir + "/" + newLabel
271 }
272 }
273 newPath.Label = newLabel
274
275 return newPath
276}
277
278// Transform paths to acknowledge package boundaries
279// See transformSubpackagePath() for more information
280func transformSubpackagePaths(ctx BazelConversionPathContext, paths bazel.LabelList) bazel.LabelList {
281 var newPaths bazel.LabelList
282 for _, include := range paths.Includes {
283 newPaths.Includes = append(newPaths.Includes, transformSubpackagePath(ctx, include))
284 }
285 for _, exclude := range paths.Excludes {
286 newPaths.Excludes = append(newPaths.Excludes, transformSubpackagePath(ctx, exclude))
287 }
288 return newPaths
289}
290
Romain Jobredeaux1282c422021-10-29 10:52:59 -0400291// Converts root-relative Paths to a list of bazel.Label relative to the module in ctx.
292func RootToModuleRelativePaths(ctx BazelConversionPathContext, paths Paths) []bazel.Label {
293 var newPaths []bazel.Label
294 for _, path := range PathsWithModuleSrcSubDir(ctx, paths, "") {
295 s := path.Rel()
296 newPaths = append(newPaths, bazel.Label{Label: s})
297 }
298 return newPaths
299}
300
Liz Kammer620dea62021-04-14 17:36:10 -0400301// expandSrcsForBazel returns bazel.LabelList with paths rooted from the module's local source
302// directory and Bazel target labels, excluding those included in the excludes argument (which
303// should already be expanded to resolve references to Soong-modules). Valid elements of paths
304// include:
305// * filepath, relative to local module directory, resolves as a filepath relative to the local
306// source directory
307// * glob, relative to the local module directory, resolves as filepath(s), relative to the local
308// module directory. Because Soong does not have a concept of crossing package boundaries, the
309// glob as computed by Soong may contain paths that cross package-boundaries that would be
310// unknowingly omitted if the glob were handled by Bazel. To allow identification and detect
311// (within Bazel) use of paths that cross package boundaries, we expand globs within Soong rather
312// than converting Soong glob syntax to Bazel glob syntax. **Invalid for excludes.**
313// * other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
314// or OutputFileProducer. These resolve as a Bazel label for a target. If the Bazel target is in
315// the local module directory, it will be returned relative to the current package (e.g.
316// ":<target>"). Otherwise, it will be returned as an absolute Bazel label (e.g.
317// "//path/to/dir:<target>"). If the reference to another module cannot be resolved,the function
318// will panic.
319// Properties passed as the paths or excludes argument must have been annotated with struct tag
320// `android:"path"` so that dependencies on other modules will have already been handled by the
321// path_deps mutator.
Jingwen Chen55bc8202021-11-02 06:40:51 +0000322func expandSrcsForBazel(ctx BazelConversionPathContext, paths, expandedExcludes []string) bazel.LabelList {
Liz Kammer620dea62021-04-14 17:36:10 -0400323 if paths == nil {
324 return bazel.LabelList{}
325 }
326 labels := bazel.LabelList{
327 Includes: []bazel.Label{},
328 }
Jingwen Chen4ecc67d2021-04-27 09:47:02 +0000329
330 // expandedExcludes contain module-dir relative paths, but root-relative paths
331 // are needed for GlobFiles later.
332 var rootRelativeExpandedExcludes []string
333 for _, e := range expandedExcludes {
334 rootRelativeExpandedExcludes = append(rootRelativeExpandedExcludes, filepath.Join(ctx.ModuleDir(), e))
335 }
336
Liz Kammer620dea62021-04-14 17:36:10 -0400337 for _, p := range paths {
338 if m, tag := SrcIsModuleWithTag(p); m != "" {
Chris Parsons953b3562021-09-20 15:14:39 -0400339 l := getOtherModuleLabel(ctx, m, tag, BazelModuleLabel)
Liz Kammerdaa09ef2021-12-15 15:35:38 -0500340 if l != nil && !InList(l.Label, expandedExcludes) {
Jingwen Chen38e62642021-04-19 05:00:15 +0000341 l.OriginalModuleName = fmt.Sprintf(":%s", m)
Liz Kammerdaa09ef2021-12-15 15:35:38 -0500342 labels.Includes = append(labels.Includes, *l)
Liz Kammer620dea62021-04-14 17:36:10 -0400343 }
344 } else {
345 var expandedPaths []bazel.Label
346 if pathtools.IsGlob(p) {
Jingwen Chen4ecc67d2021-04-27 09:47:02 +0000347 // e.g. turn "math/*.c" in
348 // external/arm-optimized-routines to external/arm-optimized-routines/math/*.c
349 rootRelativeGlobPath := pathForModuleSrc(ctx, p).String()
Romain Jobredeaux1282c422021-10-29 10:52:59 -0400350 expandedPaths = RootToModuleRelativePaths(ctx, GlobFiles(ctx, rootRelativeGlobPath, rootRelativeExpandedExcludes))
Liz Kammer620dea62021-04-14 17:36:10 -0400351 } else {
352 if !InList(p, expandedExcludes) {
353 expandedPaths = append(expandedPaths, bazel.Label{Label: p})
354 }
355 }
356 labels.Includes = append(labels.Includes, expandedPaths...)
357 }
358 }
359 return labels
360}
361
362// getOtherModuleLabel returns a bazel.Label for the given dependency/tag combination for the
363// module. The label will be relative to the current directory if appropriate. The dependency must
364// already be resolved by either deps mutator or path deps mutator.
Jingwen Chen55bc8202021-11-02 06:40:51 +0000365func getOtherModuleLabel(ctx BazelConversionPathContext, dep, tag string,
Liz Kammerdaa09ef2021-12-15 15:35:38 -0500366 labelFromModule func(BazelConversionPathContext, blueprint.Module) string) *bazel.Label {
Chris Parsons5a34ffb2021-07-21 14:34:58 -0400367 m, _ := ctx.ModuleFromName(dep)
Liz Kammerdaa09ef2021-12-15 15:35:38 -0500368 // The module was not found in an Android.bp file, this is often due to:
369 // * a limited manifest
370 // * a required module not being converted from Android.mk
Liz Kammer620dea62021-04-14 17:36:10 -0400371 if m == nil {
Liz Kammerdaa09ef2021-12-15 15:35:38 -0500372 ctx.AddMissingBp2buildDep(dep)
373 return &bazel.Label{
374 Label: ":" + dep + "__BP2BUILD__MISSING__DEP",
375 }
Liz Kammer620dea62021-04-14 17:36:10 -0400376 }
Liz Kammer6eff3232021-08-26 08:37:59 -0400377 if !convertedToBazel(ctx, m) {
378 ctx.AddUnconvertedBp2buildDep(dep)
379 }
Chris Parsons953b3562021-09-20 15:14:39 -0400380 label := BazelModuleLabel(ctx, ctx.Module())
381 otherLabel := labelFromModule(ctx, m)
382
383 // TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets.
384
Liz Kammer620dea62021-04-14 17:36:10 -0400385 if samePackage(label, otherLabel) {
386 otherLabel = bazelShortLabel(otherLabel)
387 }
388
Liz Kammerdaa09ef2021-12-15 15:35:38 -0500389 return &bazel.Label{
Liz Kammer620dea62021-04-14 17:36:10 -0400390 Label: otherLabel,
391 }
392}
393
Jingwen Chen55bc8202021-11-02 06:40:51 +0000394func BazelModuleLabel(ctx BazelConversionPathContext, module blueprint.Module) string {
Liz Kammer620dea62021-04-14 17:36:10 -0400395 // TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets.
Liz Kammer6eff3232021-08-26 08:37:59 -0400396 if !convertedToBazel(ctx, module) {
Liz Kammer620dea62021-04-14 17:36:10 -0400397 return bp2buildModuleLabel(ctx, module)
398 }
Liz Kammer6eff3232021-08-26 08:37:59 -0400399 b, _ := module.(Bazelable)
Liz Kammer620dea62021-04-14 17:36:10 -0400400 return b.GetBazelLabel(ctx, module)
401}
402
403func bazelShortLabel(label string) string {
404 i := strings.Index(label, ":")
Jingwen Chen80b6b642021-11-02 06:23:07 +0000405 if i == -1 {
406 panic(fmt.Errorf("Could not find the ':' character in '%s', expected a fully qualified label.", label))
407 }
Liz Kammer620dea62021-04-14 17:36:10 -0400408 return label[i:]
409}
410
411func bazelPackage(label string) string {
412 i := strings.Index(label, ":")
Jingwen Chen80b6b642021-11-02 06:23:07 +0000413 if i == -1 {
414 panic(fmt.Errorf("Could not find the ':' character in '%s', expected a fully qualified label.", label))
415 }
Liz Kammer620dea62021-04-14 17:36:10 -0400416 return label[0:i]
417}
418
419func samePackage(label1, label2 string) bool {
420 return bazelPackage(label1) == bazelPackage(label2)
421}
422
Jingwen Chen55bc8202021-11-02 06:40:51 +0000423func bp2buildModuleLabel(ctx BazelConversionContext, module blueprint.Module) string {
Liz Kammer620dea62021-04-14 17:36:10 -0400424 moduleName := ctx.OtherModuleName(module)
425 moduleDir := ctx.OtherModuleDir(module)
426 return fmt.Sprintf("//%s:%s", moduleDir, moduleName)
427}
428
429// BazelOutPath is a Bazel output path compatible to be used for mixed builds within Soong/Ninja.
430type BazelOutPath struct {
431 OutputPath
432}
433
Liz Kammer0f3b7d22021-09-28 13:48:21 -0400434// ensure BazelOutPath implements Path
Liz Kammer620dea62021-04-14 17:36:10 -0400435var _ Path = BazelOutPath{}
Liz Kammer0f3b7d22021-09-28 13:48:21 -0400436
437// ensure BazelOutPath implements genPathProvider
438var _ genPathProvider = BazelOutPath{}
439
440// ensure BazelOutPath implements objPathProvider
Liz Kammer620dea62021-04-14 17:36:10 -0400441var _ objPathProvider = BazelOutPath{}
442
Liz Kammer0f3b7d22021-09-28 13:48:21 -0400443func (p BazelOutPath) genPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleGenPath {
444 return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
445}
446
Liz Kammer620dea62021-04-14 17:36:10 -0400447func (p BazelOutPath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath {
448 return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
449}
450
451// PathForBazelOut returns a Path representing the paths... under an output directory dedicated to
452// bazel-owned outputs.
453func PathForBazelOut(ctx PathContext, paths ...string) BazelOutPath {
454 execRootPathComponents := append([]string{"execroot", "__main__"}, paths...)
455 execRootPath := filepath.Join(execRootPathComponents...)
456 validatedExecRootPath, err := validatePath(execRootPath)
457 if err != nil {
458 reportPathError(ctx, err)
459 }
460
461 outputPath := OutputPath{basePath{"", ""},
Lukacs T. Berki9f6c24a2021-08-26 15:07:24 +0200462 ctx.Config().soongOutDir,
Liz Kammer620dea62021-04-14 17:36:10 -0400463 ctx.Config().BazelContext.OutputBase()}
464
465 return BazelOutPath{
466 OutputPath: outputPath.withRel(validatedExecRootPath),
467 }
468}
Liz Kammerb6a55bf2021-04-12 15:42:51 -0400469
470// PathsForBazelOut returns a list of paths representing the paths under an output directory
471// dedicated to Bazel-owned outputs.
472func PathsForBazelOut(ctx PathContext, paths []string) Paths {
473 outs := make(Paths, 0, len(paths))
474 for _, p := range paths {
475 outs = append(outs, PathForBazelOut(ctx, p))
476 }
477 return outs
478}