Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 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 | |
| 15 | package android |
| 16 | |
| 17 | import ( |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 18 | "fmt" |
| 19 | "path/filepath" |
| 20 | "strings" |
| 21 | |
Chris Parsons | 953b356 | 2021-09-20 15:14:39 -0400 | [diff] [blame] | 22 | "android/soong/bazel" |
| 23 | |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 24 | "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 Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame^] | 71 | // 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. |
| 75 | type BazelConversionContext interface { |
| 76 | Config() Config |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 77 | |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 78 | Module() Module |
Liz Kammer | 6eff323 | 2021-08-26 08:37:59 -0400 | [diff] [blame] | 79 | OtherModuleType(m blueprint.Module) string |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 80 | OtherModuleName(m blueprint.Module) string |
| 81 | OtherModuleDir(m blueprint.Module) string |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame^] | 82 | } |
| 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. |
| 86 | type 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 Kammer | 6eff323 | 2021-08-26 08:37:59 -0400 | [diff] [blame] | 94 | AddUnconvertedBp2buildDep(string) |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 95 | } |
| 96 | |
| 97 | // BazelLabelForModuleDeps expects a list of reference to other modules, ("<module>" |
| 98 | // or ":<module>") and returns a Bazel-compatible label which corresponds to dependencies on the |
| 99 | // module within the given ctx. |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame^] | 100 | func BazelLabelForModuleDeps(ctx BazelConversionPathContext, modules []string) bazel.LabelList { |
Chris Parsons | 953b356 | 2021-09-20 15:14:39 -0400 | [diff] [blame] | 101 | return BazelLabelForModuleDepsWithFn(ctx, modules, BazelModuleLabel) |
Liz Kammer | 2d7bbe3 | 2021-06-10 18:20:06 -0400 | [diff] [blame] | 102 | } |
| 103 | |
| 104 | // BazelLabelForModuleWholeDepsExcludes expects two lists: modules (containing modules to include in |
| 105 | // the list), and excludes (modules to exclude from the list). Both of these should contain |
| 106 | // references to other modules, ("<module>" or ":<module>"). It returns a Bazel-compatible label |
| 107 | // list which corresponds to dependencies on the module within the given ctx, and the excluded |
| 108 | // dependencies. Prebuilt dependencies will be appended with _alwayslink so they can be handled as |
| 109 | // whole static libraries. |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame^] | 110 | func BazelLabelForModuleDepsExcludes(ctx BazelConversionPathContext, modules, excludes []string) bazel.LabelList { |
Chris Parsons | 953b356 | 2021-09-20 15:14:39 -0400 | [diff] [blame] | 111 | return BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, BazelModuleLabel) |
Liz Kammer | 2d7bbe3 | 2021-06-10 18:20:06 -0400 | [diff] [blame] | 112 | } |
| 113 | |
Chris Parsons | 953b356 | 2021-09-20 15:14:39 -0400 | [diff] [blame] | 114 | // BazelLabelForModuleDepsWithFn expects a list of reference to other modules, ("<module>" |
| 115 | // or ":<module>") and applies moduleToLabelFn to determine and return a Bazel-compatible label |
| 116 | // which corresponds to dependencies on the module within the given ctx. |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame^] | 117 | func BazelLabelForModuleDepsWithFn(ctx BazelConversionPathContext, modules []string, |
| 118 | moduleToLabelFn func(BazelConversionPathContext, blueprint.Module) string) bazel.LabelList { |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 119 | var labels bazel.LabelList |
Chris Parsons | 51f8c39 | 2021-08-03 21:01:05 -0400 | [diff] [blame] | 120 | // In some cases, a nil string list is different than an explicitly empty list. |
| 121 | if len(modules) == 0 && modules != nil { |
| 122 | labels.Includes = []bazel.Label{} |
| 123 | return labels |
| 124 | } |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 125 | for _, module := range modules { |
| 126 | bpText := module |
| 127 | if m := SrcIsModule(module); m == "" { |
| 128 | module = ":" + module |
| 129 | } |
| 130 | if m, t := SrcIsModuleWithTag(module); m != "" { |
Chris Parsons | 953b356 | 2021-09-20 15:14:39 -0400 | [diff] [blame] | 131 | l := getOtherModuleLabel(ctx, m, t, moduleToLabelFn) |
Jingwen Chen | 38e6264 | 2021-04-19 05:00:15 +0000 | [diff] [blame] | 132 | l.OriginalModuleName = bpText |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 133 | labels.Includes = append(labels.Includes, l) |
| 134 | } else { |
| 135 | ctx.ModuleErrorf("%q, is not a module reference", module) |
| 136 | } |
| 137 | } |
| 138 | return labels |
| 139 | } |
| 140 | |
Chris Parsons | 953b356 | 2021-09-20 15:14:39 -0400 | [diff] [blame] | 141 | // BazelLabelForModuleDepsExcludesWithFn expects two lists: modules (containing modules to include in the |
| 142 | // list), and excludes (modules to exclude from the list). Both of these should contain references |
| 143 | // to other modules, ("<module>" or ":<module>"). It applies moduleToLabelFn to determine and return a |
| 144 | // Bazel-compatible label list which corresponds to dependencies on the module within the given ctx, and |
| 145 | // the excluded dependencies. |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame^] | 146 | func BazelLabelForModuleDepsExcludesWithFn(ctx BazelConversionPathContext, modules, excludes []string, |
| 147 | moduleToLabelFn func(BazelConversionPathContext, blueprint.Module) string) bazel.LabelList { |
Chris Parsons | 953b356 | 2021-09-20 15:14:39 -0400 | [diff] [blame] | 148 | moduleLabels := BazelLabelForModuleDepsWithFn(ctx, RemoveListFromList(modules, excludes), moduleToLabelFn) |
Liz Kammer | 47535c5 | 2021-06-02 16:02:22 -0400 | [diff] [blame] | 149 | if len(excludes) == 0 { |
| 150 | return moduleLabels |
| 151 | } |
Chris Parsons | 953b356 | 2021-09-20 15:14:39 -0400 | [diff] [blame] | 152 | excludeLabels := BazelLabelForModuleDepsWithFn(ctx, excludes, moduleToLabelFn) |
Liz Kammer | 47535c5 | 2021-06-02 16:02:22 -0400 | [diff] [blame] | 153 | return bazel.LabelList{ |
| 154 | Includes: moduleLabels.Includes, |
| 155 | Excludes: excludeLabels.Includes, |
| 156 | } |
| 157 | } |
| 158 | |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame^] | 159 | func BazelLabelForModuleSrcSingle(ctx BazelConversionPathContext, path string) bazel.Label { |
Lukacs T. Berki | 1353e59 | 2021-04-30 15:35:09 +0200 | [diff] [blame] | 160 | return BazelLabelForModuleSrcExcludes(ctx, []string{path}, []string(nil)).Includes[0] |
| 161 | } |
| 162 | |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame^] | 163 | func BazelLabelForModuleDepSingle(ctx BazelConversionPathContext, path string) bazel.Label { |
Rupert Shuttleworth | 6e4950a | 2021-07-27 01:34:59 -0400 | [diff] [blame] | 164 | return BazelLabelForModuleDepsExcludes(ctx, []string{path}, []string(nil)).Includes[0] |
| 165 | } |
| 166 | |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 167 | // BazelLabelForModuleSrc expects a list of path (relative to local module directory) and module |
| 168 | // references (":<module>") and returns a bazel.LabelList{} containing the resolved references in |
| 169 | // paths, relative to the local module, or Bazel-labels (absolute if in a different package or |
| 170 | // relative if within the same package). |
| 171 | // Properties must have been annotated with struct tag `android:"path"` so that dependencies modules |
| 172 | // will have already been handled by the path_deps mutator. |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame^] | 173 | func BazelLabelForModuleSrc(ctx BazelConversionPathContext, paths []string) bazel.LabelList { |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 174 | return BazelLabelForModuleSrcExcludes(ctx, paths, []string(nil)) |
| 175 | } |
| 176 | |
| 177 | // BazelLabelForModuleSrc expects lists of path and excludes (relative to local module directory) |
| 178 | // and module references (":<module>") and returns a bazel.LabelList{} containing the resolved |
| 179 | // references in paths, minus those in excludes, relative to the local module, or Bazel-labels |
| 180 | // (absolute if in a different package or relative if within the same package). |
| 181 | // Properties must have been annotated with struct tag `android:"path"` so that dependencies modules |
| 182 | // will have already been handled by the path_deps mutator. |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame^] | 183 | func BazelLabelForModuleSrcExcludes(ctx BazelConversionPathContext, paths, excludes []string) bazel.LabelList { |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 184 | excludeLabels := expandSrcsForBazel(ctx, excludes, []string(nil)) |
| 185 | excluded := make([]string, 0, len(excludeLabels.Includes)) |
| 186 | for _, e := range excludeLabels.Includes { |
| 187 | excluded = append(excluded, e.Label) |
| 188 | } |
| 189 | labels := expandSrcsForBazel(ctx, paths, excluded) |
| 190 | labels.Excludes = excludeLabels.Includes |
| 191 | labels = transformSubpackagePaths(ctx, labels) |
| 192 | return labels |
| 193 | } |
| 194 | |
| 195 | // Returns true if a prefix + components[:i] + /Android.bp exists |
| 196 | // TODO(b/185358476) Could check for BUILD file instead of checking for Android.bp file, or ensure BUILD is always generated? |
| 197 | func directoryHasBlueprint(fs pathtools.FileSystem, prefix string, components []string, componentIndex int) bool { |
| 198 | blueprintPath := prefix |
| 199 | if blueprintPath != "" { |
| 200 | blueprintPath = blueprintPath + "/" |
| 201 | } |
| 202 | blueprintPath = blueprintPath + strings.Join(components[:componentIndex+1], "/") |
| 203 | blueprintPath = blueprintPath + "/Android.bp" |
| 204 | if exists, _, _ := fs.Exists(blueprintPath); exists { |
| 205 | return true |
| 206 | } else { |
| 207 | return false |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | // Transform a path (if necessary) to acknowledge package boundaries |
| 212 | // |
| 213 | // e.g. something like |
| 214 | // async_safe/include/async_safe/CHECK.h |
| 215 | // might become |
| 216 | // //bionic/libc/async_safe:include/async_safe/CHECK.h |
| 217 | // if the "async_safe" directory is actually a package and not just a directory. |
| 218 | // |
| 219 | // In particular, paths that extend into packages are transformed into absolute labels beginning with //. |
| 220 | func transformSubpackagePath(ctx BazelConversionPathContext, path bazel.Label) bazel.Label { |
| 221 | var newPath bazel.Label |
| 222 | |
Jingwen Chen | 38e6264 | 2021-04-19 05:00:15 +0000 | [diff] [blame] | 223 | // Don't transform OriginalModuleName |
| 224 | newPath.OriginalModuleName = path.OriginalModuleName |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 225 | |
| 226 | if strings.HasPrefix(path.Label, "//") { |
| 227 | // Assume absolute labels are already correct (e.g. //path/to/some/package:foo.h) |
| 228 | newPath.Label = path.Label |
| 229 | return newPath |
| 230 | } |
| 231 | |
| 232 | newLabel := "" |
| 233 | pathComponents := strings.Split(path.Label, "/") |
| 234 | foundBlueprint := false |
| 235 | // Check the deepest subdirectory first and work upwards |
| 236 | for i := len(pathComponents) - 1; i >= 0; i-- { |
| 237 | pathComponent := pathComponents[i] |
| 238 | var sep string |
| 239 | if !foundBlueprint && directoryHasBlueprint(ctx.Config().fs, ctx.ModuleDir(), pathComponents, i) { |
| 240 | sep = ":" |
| 241 | foundBlueprint = true |
| 242 | } else { |
| 243 | sep = "/" |
| 244 | } |
| 245 | if newLabel == "" { |
| 246 | newLabel = pathComponent |
| 247 | } else { |
| 248 | newLabel = pathComponent + sep + newLabel |
| 249 | } |
| 250 | } |
| 251 | if foundBlueprint { |
| 252 | // Ensure paths end up looking like //bionic/... instead of //./bionic/... |
| 253 | moduleDir := ctx.ModuleDir() |
| 254 | if strings.HasPrefix(moduleDir, ".") { |
| 255 | moduleDir = moduleDir[1:] |
| 256 | } |
| 257 | // Make the path into an absolute label (e.g. //bionic/libc/foo:bar.h instead of just foo:bar.h) |
| 258 | if moduleDir == "" { |
| 259 | newLabel = "//" + newLabel |
| 260 | } else { |
| 261 | newLabel = "//" + moduleDir + "/" + newLabel |
| 262 | } |
| 263 | } |
| 264 | newPath.Label = newLabel |
| 265 | |
| 266 | return newPath |
| 267 | } |
| 268 | |
| 269 | // Transform paths to acknowledge package boundaries |
| 270 | // See transformSubpackagePath() for more information |
| 271 | func transformSubpackagePaths(ctx BazelConversionPathContext, paths bazel.LabelList) bazel.LabelList { |
| 272 | var newPaths bazel.LabelList |
| 273 | for _, include := range paths.Includes { |
| 274 | newPaths.Includes = append(newPaths.Includes, transformSubpackagePath(ctx, include)) |
| 275 | } |
| 276 | for _, exclude := range paths.Excludes { |
| 277 | newPaths.Excludes = append(newPaths.Excludes, transformSubpackagePath(ctx, exclude)) |
| 278 | } |
| 279 | return newPaths |
| 280 | } |
| 281 | |
| 282 | // expandSrcsForBazel returns bazel.LabelList with paths rooted from the module's local source |
| 283 | // directory and Bazel target labels, excluding those included in the excludes argument (which |
| 284 | // should already be expanded to resolve references to Soong-modules). Valid elements of paths |
| 285 | // include: |
| 286 | // * filepath, relative to local module directory, resolves as a filepath relative to the local |
| 287 | // source directory |
| 288 | // * glob, relative to the local module directory, resolves as filepath(s), relative to the local |
| 289 | // module directory. Because Soong does not have a concept of crossing package boundaries, the |
| 290 | // glob as computed by Soong may contain paths that cross package-boundaries that would be |
| 291 | // unknowingly omitted if the glob were handled by Bazel. To allow identification and detect |
| 292 | // (within Bazel) use of paths that cross package boundaries, we expand globs within Soong rather |
| 293 | // than converting Soong glob syntax to Bazel glob syntax. **Invalid for excludes.** |
| 294 | // * other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer |
| 295 | // or OutputFileProducer. These resolve as a Bazel label for a target. If the Bazel target is in |
| 296 | // the local module directory, it will be returned relative to the current package (e.g. |
| 297 | // ":<target>"). Otherwise, it will be returned as an absolute Bazel label (e.g. |
| 298 | // "//path/to/dir:<target>"). If the reference to another module cannot be resolved,the function |
| 299 | // will panic. |
| 300 | // Properties passed as the paths or excludes argument must have been annotated with struct tag |
| 301 | // `android:"path"` so that dependencies on other modules will have already been handled by the |
| 302 | // path_deps mutator. |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame^] | 303 | func expandSrcsForBazel(ctx BazelConversionPathContext, paths, expandedExcludes []string) bazel.LabelList { |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 304 | if paths == nil { |
| 305 | return bazel.LabelList{} |
| 306 | } |
| 307 | labels := bazel.LabelList{ |
| 308 | Includes: []bazel.Label{}, |
| 309 | } |
Jingwen Chen | 4ecc67d | 2021-04-27 09:47:02 +0000 | [diff] [blame] | 310 | |
| 311 | // expandedExcludes contain module-dir relative paths, but root-relative paths |
| 312 | // are needed for GlobFiles later. |
| 313 | var rootRelativeExpandedExcludes []string |
| 314 | for _, e := range expandedExcludes { |
| 315 | rootRelativeExpandedExcludes = append(rootRelativeExpandedExcludes, filepath.Join(ctx.ModuleDir(), e)) |
| 316 | } |
| 317 | |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 318 | for _, p := range paths { |
| 319 | if m, tag := SrcIsModuleWithTag(p); m != "" { |
Chris Parsons | 953b356 | 2021-09-20 15:14:39 -0400 | [diff] [blame] | 320 | l := getOtherModuleLabel(ctx, m, tag, BazelModuleLabel) |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 321 | if !InList(l.Label, expandedExcludes) { |
Jingwen Chen | 38e6264 | 2021-04-19 05:00:15 +0000 | [diff] [blame] | 322 | l.OriginalModuleName = fmt.Sprintf(":%s", m) |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 323 | labels.Includes = append(labels.Includes, l) |
| 324 | } |
| 325 | } else { |
| 326 | var expandedPaths []bazel.Label |
| 327 | if pathtools.IsGlob(p) { |
Jingwen Chen | 4ecc67d | 2021-04-27 09:47:02 +0000 | [diff] [blame] | 328 | // e.g. turn "math/*.c" in |
| 329 | // external/arm-optimized-routines to external/arm-optimized-routines/math/*.c |
| 330 | rootRelativeGlobPath := pathForModuleSrc(ctx, p).String() |
| 331 | globbedPaths := GlobFiles(ctx, rootRelativeGlobPath, rootRelativeExpandedExcludes) |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 332 | globbedPaths = PathsWithModuleSrcSubDir(ctx, globbedPaths, "") |
| 333 | for _, path := range globbedPaths { |
| 334 | s := path.Rel() |
| 335 | expandedPaths = append(expandedPaths, bazel.Label{Label: s}) |
| 336 | } |
| 337 | } else { |
| 338 | if !InList(p, expandedExcludes) { |
| 339 | expandedPaths = append(expandedPaths, bazel.Label{Label: p}) |
| 340 | } |
| 341 | } |
| 342 | labels.Includes = append(labels.Includes, expandedPaths...) |
| 343 | } |
| 344 | } |
| 345 | return labels |
| 346 | } |
| 347 | |
| 348 | // getOtherModuleLabel returns a bazel.Label for the given dependency/tag combination for the |
| 349 | // module. The label will be relative to the current directory if appropriate. The dependency must |
| 350 | // already be resolved by either deps mutator or path deps mutator. |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame^] | 351 | func getOtherModuleLabel(ctx BazelConversionPathContext, dep, tag string, |
| 352 | labelFromModule func(BazelConversionPathContext, blueprint.Module) string) bazel.Label { |
Chris Parsons | 5a34ffb | 2021-07-21 14:34:58 -0400 | [diff] [blame] | 353 | m, _ := ctx.ModuleFromName(dep) |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 354 | if m == nil { |
Chris Parsons | 5a34ffb | 2021-07-21 14:34:58 -0400 | [diff] [blame] | 355 | panic(fmt.Errorf("No module named %q found, but was a direct dep of %q", dep, ctx.Module().Name())) |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 356 | } |
Liz Kammer | 6eff323 | 2021-08-26 08:37:59 -0400 | [diff] [blame] | 357 | if !convertedToBazel(ctx, m) { |
| 358 | ctx.AddUnconvertedBp2buildDep(dep) |
| 359 | } |
Chris Parsons | 953b356 | 2021-09-20 15:14:39 -0400 | [diff] [blame] | 360 | label := BazelModuleLabel(ctx, ctx.Module()) |
| 361 | otherLabel := labelFromModule(ctx, m) |
| 362 | |
| 363 | // TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets. |
| 364 | |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 365 | if samePackage(label, otherLabel) { |
| 366 | otherLabel = bazelShortLabel(otherLabel) |
| 367 | } |
| 368 | |
| 369 | return bazel.Label{ |
| 370 | Label: otherLabel, |
| 371 | } |
| 372 | } |
| 373 | |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame^] | 374 | func BazelModuleLabel(ctx BazelConversionPathContext, module blueprint.Module) string { |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 375 | // TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets. |
Liz Kammer | 6eff323 | 2021-08-26 08:37:59 -0400 | [diff] [blame] | 376 | if !convertedToBazel(ctx, module) { |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 377 | return bp2buildModuleLabel(ctx, module) |
| 378 | } |
Liz Kammer | 6eff323 | 2021-08-26 08:37:59 -0400 | [diff] [blame] | 379 | b, _ := module.(Bazelable) |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 380 | return b.GetBazelLabel(ctx, module) |
| 381 | } |
| 382 | |
| 383 | func bazelShortLabel(label string) string { |
| 384 | i := strings.Index(label, ":") |
Jingwen Chen | 80b6b64 | 2021-11-02 06:23:07 +0000 | [diff] [blame] | 385 | if i == -1 { |
| 386 | panic(fmt.Errorf("Could not find the ':' character in '%s', expected a fully qualified label.", label)) |
| 387 | } |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 388 | return label[i:] |
| 389 | } |
| 390 | |
| 391 | func bazelPackage(label string) string { |
| 392 | i := strings.Index(label, ":") |
Jingwen Chen | 80b6b64 | 2021-11-02 06:23:07 +0000 | [diff] [blame] | 393 | if i == -1 { |
| 394 | panic(fmt.Errorf("Could not find the ':' character in '%s', expected a fully qualified label.", label)) |
| 395 | } |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 396 | return label[0:i] |
| 397 | } |
| 398 | |
| 399 | func samePackage(label1, label2 string) bool { |
| 400 | return bazelPackage(label1) == bazelPackage(label2) |
| 401 | } |
| 402 | |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame^] | 403 | func bp2buildModuleLabel(ctx BazelConversionContext, module blueprint.Module) string { |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 404 | moduleName := ctx.OtherModuleName(module) |
| 405 | moduleDir := ctx.OtherModuleDir(module) |
| 406 | return fmt.Sprintf("//%s:%s", moduleDir, moduleName) |
| 407 | } |
| 408 | |
| 409 | // BazelOutPath is a Bazel output path compatible to be used for mixed builds within Soong/Ninja. |
| 410 | type BazelOutPath struct { |
| 411 | OutputPath |
| 412 | } |
| 413 | |
Liz Kammer | 0f3b7d2 | 2021-09-28 13:48:21 -0400 | [diff] [blame] | 414 | // ensure BazelOutPath implements Path |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 415 | var _ Path = BazelOutPath{} |
Liz Kammer | 0f3b7d2 | 2021-09-28 13:48:21 -0400 | [diff] [blame] | 416 | |
| 417 | // ensure BazelOutPath implements genPathProvider |
| 418 | var _ genPathProvider = BazelOutPath{} |
| 419 | |
| 420 | // ensure BazelOutPath implements objPathProvider |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 421 | var _ objPathProvider = BazelOutPath{} |
| 422 | |
Liz Kammer | 0f3b7d2 | 2021-09-28 13:48:21 -0400 | [diff] [blame] | 423 | func (p BazelOutPath) genPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleGenPath { |
| 424 | return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext)) |
| 425 | } |
| 426 | |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 427 | func (p BazelOutPath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath { |
| 428 | return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext)) |
| 429 | } |
| 430 | |
| 431 | // PathForBazelOut returns a Path representing the paths... under an output directory dedicated to |
| 432 | // bazel-owned outputs. |
| 433 | func PathForBazelOut(ctx PathContext, paths ...string) BazelOutPath { |
| 434 | execRootPathComponents := append([]string{"execroot", "__main__"}, paths...) |
| 435 | execRootPath := filepath.Join(execRootPathComponents...) |
| 436 | validatedExecRootPath, err := validatePath(execRootPath) |
| 437 | if err != nil { |
| 438 | reportPathError(ctx, err) |
| 439 | } |
| 440 | |
| 441 | outputPath := OutputPath{basePath{"", ""}, |
Lukacs T. Berki | 9f6c24a | 2021-08-26 15:07:24 +0200 | [diff] [blame] | 442 | ctx.Config().soongOutDir, |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 443 | ctx.Config().BazelContext.OutputBase()} |
| 444 | |
| 445 | return BazelOutPath{ |
| 446 | OutputPath: outputPath.withRel(validatedExecRootPath), |
| 447 | } |
| 448 | } |
Liz Kammer | b6a55bf | 2021-04-12 15:42:51 -0400 | [diff] [blame] | 449 | |
| 450 | // PathsForBazelOut returns a list of paths representing the paths under an output directory |
| 451 | // dedicated to Bazel-owned outputs. |
| 452 | func PathsForBazelOut(ctx PathContext, paths []string) Paths { |
| 453 | outs := make(Paths, 0, len(paths)) |
| 454 | for _, p := range paths { |
| 455 | outs = append(outs, PathForBazelOut(ctx, p)) |
| 456 | } |
| 457 | return outs |
| 458 | } |