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" |
Spandan Das | dc7d7f7 | 2023-09-28 21:23:30 +0000 | [diff] [blame] | 19 | "os" |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 20 | "path/filepath" |
| 21 | "strings" |
| 22 | |
Chris Parsons | 953b356 | 2021-09-20 15:14:39 -0400 | [diff] [blame] | 23 | "android/soong/bazel" |
| 24 | |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 25 | "github.com/google/blueprint" |
| 26 | "github.com/google/blueprint/pathtools" |
| 27 | ) |
| 28 | |
| 29 | // bazel_paths contains methods to: |
| 30 | // * resolve Soong path and module references into bazel.LabelList |
| 31 | // * resolve Bazel path references into Soong-compatible paths |
| 32 | // |
| 33 | // There is often a similar method for Bazel as there is for Soong path handling and should be used |
| 34 | // in similar circumstances |
| 35 | // |
Usta Shrestha | db46a9b | 2022-07-11 11:29:56 -0400 | [diff] [blame] | 36 | // Bazel Soong |
| 37 | // ============================================================== |
| 38 | // BazelLabelForModuleSrc PathForModuleSrc |
| 39 | // BazelLabelForModuleSrcExcludes PathForModuleSrcExcludes |
| 40 | // BazelLabelForModuleDeps n/a |
| 41 | // tbd PathForSource |
| 42 | // tbd ExistentPathsForSources |
| 43 | // PathForBazelOut PathForModuleOut |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 44 | // |
| 45 | // Use cases: |
| 46 | // * Module contains a property (often tagged `android:"path"`) that expects paths *relative to the |
| 47 | // module directory*: |
| 48 | // * BazelLabelForModuleSrcExcludes, if the module also contains an excludes_<propname> property |
| 49 | // * BazelLabelForModuleSrc, otherwise |
| 50 | // * Converting references to other modules to Bazel Labels: |
| 51 | // BazelLabelForModuleDeps |
| 52 | // * Converting a path obtained from bazel_handler cquery results: |
| 53 | // PathForBazelOut |
| 54 | // |
| 55 | // NOTE: all Soong globs are expanded within Soong rather than being converted to a Bazel glob |
| 56 | // syntax. This occurs because Soong does not have a concept of crossing package boundaries, |
| 57 | // so the glob as computed by Soong may contain paths that cross package-boundaries. These |
| 58 | // would be unknowingly omitted if the glob were handled by Bazel. By expanding globs within |
| 59 | // Soong, we support identification and detection (within Bazel) use of paths that cross |
| 60 | // package boundaries. |
| 61 | // |
| 62 | // Path resolution: |
| 63 | // * filepath/globs: resolves as itself or is converted to an absolute Bazel label (e.g. |
| 64 | // //path/to/dir:<filepath>) if path exists in a separate package or subpackage. |
| 65 | // * references to other modules (using the ":name{.tag}" syntax). These resolve as a Bazel label |
| 66 | // for a target. If the Bazel target is in the local module directory, it will be returned |
| 67 | // relative to the current package (e.g. ":<target>"). Otherwise, it will be returned as an |
| 68 | // absolute Bazel label (e.g. "//path/to/dir:<target>"). If the reference to another module |
| 69 | // cannot be resolved,the function will panic. This is often due to the dependency not being added |
| 70 | // via an AddDependency* method. |
| 71 | |
Usta Shrestha | db46a9b | 2022-07-11 11:29:56 -0400 | [diff] [blame] | 72 | // BazelConversionContext is a minimal context interface to check if a module should be converted by bp2build, |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame] | 73 | // with functions containing information to match against allowlists and denylists. |
| 74 | // If a module is deemed to be convertible by bp2build, then it should rely on a |
| 75 | // BazelConversionPathContext for more functions for dep/path features. |
| 76 | type BazelConversionContext interface { |
| 77 | Config() Config |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 78 | |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 79 | Module() Module |
Liz Kammer | 6eff323 | 2021-08-26 08:37:59 -0400 | [diff] [blame] | 80 | OtherModuleType(m blueprint.Module) string |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 81 | OtherModuleName(m blueprint.Module) string |
| 82 | OtherModuleDir(m blueprint.Module) string |
Sam Delmerico | 24c5603 | 2022-03-28 19:53:03 +0000 | [diff] [blame] | 83 | ModuleErrorf(format string, args ...interface{}) |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame] | 84 | } |
| 85 | |
| 86 | // A subset of the ModuleContext methods which are sufficient to resolve references to paths/deps in |
| 87 | // order to form a Bazel-compatible label for conversion. |
| 88 | type BazelConversionPathContext interface { |
| 89 | EarlyModulePathContext |
| 90 | BazelConversionContext |
| 91 | |
Liz Kammer | c86e094 | 2023-08-11 16:15:12 -0400 | [diff] [blame] | 92 | ModuleName() string |
| 93 | ModuleType() string |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame] | 94 | ModuleErrorf(fmt string, args ...interface{}) |
| 95 | PropertyErrorf(property, fmt string, args ...interface{}) |
| 96 | GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) |
| 97 | ModuleFromName(name string) (blueprint.Module, bool) |
Liz Kammer | 6eff323 | 2021-08-26 08:37:59 -0400 | [diff] [blame] | 98 | AddUnconvertedBp2buildDep(string) |
Liz Kammer | daa09ef | 2021-12-15 15:35:38 -0500 | [diff] [blame] | 99 | AddMissingBp2buildDep(dep string) |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 100 | } |
| 101 | |
| 102 | // BazelLabelForModuleDeps expects a list of reference to other modules, ("<module>" |
| 103 | // or ":<module>") and returns a Bazel-compatible label which corresponds to dependencies on the |
| 104 | // module within the given ctx. |
Chris Parsons | 5f1b3c7 | 2023-09-28 20:41:03 +0000 | [diff] [blame] | 105 | func BazelLabelForModuleDeps(ctx Bp2buildMutatorContext, modules []string) bazel.LabelList { |
Jingwen Chen | 3e582b8 | 2023-10-05 10:03:06 +0000 | [diff] [blame] | 106 | return BazelLabelForModuleDepsWithFn(ctx, modules, BazelModuleLabel, /*markAsDeps=*/true) |
Liz Kammer | 2d7bbe3 | 2021-06-10 18:20:06 -0400 | [diff] [blame] | 107 | } |
| 108 | |
| 109 | // BazelLabelForModuleWholeDepsExcludes expects two lists: modules (containing modules to include in |
| 110 | // the list), and excludes (modules to exclude from the list). Both of these should contain |
| 111 | // references to other modules, ("<module>" or ":<module>"). It returns a Bazel-compatible label |
| 112 | // list which corresponds to dependencies on the module within the given ctx, and the excluded |
| 113 | // dependencies. Prebuilt dependencies will be appended with _alwayslink so they can be handled as |
| 114 | // whole static libraries. |
Chris Parsons | 5f1b3c7 | 2023-09-28 20:41:03 +0000 | [diff] [blame] | 115 | func BazelLabelForModuleDepsExcludes(ctx Bp2buildMutatorContext, modules, excludes []string) bazel.LabelList { |
Chris Parsons | 953b356 | 2021-09-20 15:14:39 -0400 | [diff] [blame] | 116 | return BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, BazelModuleLabel) |
Liz Kammer | 2d7bbe3 | 2021-06-10 18:20:06 -0400 | [diff] [blame] | 117 | } |
| 118 | |
Chris Parsons | 953b356 | 2021-09-20 15:14:39 -0400 | [diff] [blame] | 119 | // BazelLabelForModuleDepsWithFn expects a list of reference to other modules, ("<module>" |
| 120 | // or ":<module>") and applies moduleToLabelFn to determine and return a Bazel-compatible label |
| 121 | // which corresponds to dependencies on the module within the given ctx. |
Chris Parsons | 5f1b3c7 | 2023-09-28 20:41:03 +0000 | [diff] [blame] | 122 | func BazelLabelForModuleDepsWithFn(ctx Bp2buildMutatorContext, modules []string, |
| 123 | moduleToLabelFn func(BazelConversionPathContext, blueprint.Module) string, |
| 124 | markAsDeps bool) bazel.LabelList { |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 125 | var labels bazel.LabelList |
Chris Parsons | 51f8c39 | 2021-08-03 21:01:05 -0400 | [diff] [blame] | 126 | // In some cases, a nil string list is different than an explicitly empty list. |
| 127 | if len(modules) == 0 && modules != nil { |
| 128 | labels.Includes = []bazel.Label{} |
| 129 | return labels |
| 130 | } |
Cole Faust | 5c84c62 | 2023-08-01 11:07:02 -0700 | [diff] [blame] | 131 | modules = FirstUniqueStrings(modules) |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 132 | for _, module := range modules { |
| 133 | bpText := module |
| 134 | if m := SrcIsModule(module); m == "" { |
| 135 | module = ":" + module |
| 136 | } |
| 137 | if m, t := SrcIsModuleWithTag(module); m != "" { |
Chris Parsons | 5f1b3c7 | 2023-09-28 20:41:03 +0000 | [diff] [blame] | 138 | l := getOtherModuleLabel(ctx, m, t, moduleToLabelFn, markAsDeps) |
Liz Kammer | daa09ef | 2021-12-15 15:35:38 -0500 | [diff] [blame] | 139 | if l != nil { |
| 140 | l.OriginalModuleName = bpText |
| 141 | labels.Includes = append(labels.Includes, *l) |
| 142 | } |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 143 | } else { |
| 144 | ctx.ModuleErrorf("%q, is not a module reference", module) |
| 145 | } |
| 146 | } |
| 147 | return labels |
| 148 | } |
| 149 | |
Chris Parsons | 953b356 | 2021-09-20 15:14:39 -0400 | [diff] [blame] | 150 | // BazelLabelForModuleDepsExcludesWithFn expects two lists: modules (containing modules to include in the |
| 151 | // list), and excludes (modules to exclude from the list). Both of these should contain references |
| 152 | // to other modules, ("<module>" or ":<module>"). It applies moduleToLabelFn to determine and return a |
| 153 | // Bazel-compatible label list which corresponds to dependencies on the module within the given ctx, and |
| 154 | // the excluded dependencies. |
Chris Parsons | 5f1b3c7 | 2023-09-28 20:41:03 +0000 | [diff] [blame] | 155 | func BazelLabelForModuleDepsExcludesWithFn(ctx Bp2buildMutatorContext, modules, excludes []string, |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame] | 156 | moduleToLabelFn func(BazelConversionPathContext, blueprint.Module) string) bazel.LabelList { |
Jingwen Chen | 3e582b8 | 2023-10-05 10:03:06 +0000 | [diff] [blame] | 157 | moduleLabels := BazelLabelForModuleDepsWithFn(ctx, RemoveListFromList(modules, excludes), moduleToLabelFn, /*markAsDeps=*/true) |
Liz Kammer | 47535c5 | 2021-06-02 16:02:22 -0400 | [diff] [blame] | 158 | if len(excludes) == 0 { |
| 159 | return moduleLabels |
| 160 | } |
Jingwen Chen | 3e582b8 | 2023-10-05 10:03:06 +0000 | [diff] [blame] | 161 | excludeLabels := BazelLabelForModuleDepsWithFn(ctx, excludes, moduleToLabelFn, /*markAsDeps=*/false) |
Liz Kammer | 47535c5 | 2021-06-02 16:02:22 -0400 | [diff] [blame] | 162 | return bazel.LabelList{ |
| 163 | Includes: moduleLabels.Includes, |
| 164 | Excludes: excludeLabels.Includes, |
| 165 | } |
| 166 | } |
| 167 | |
Chris Parsons | 5f1b3c7 | 2023-09-28 20:41:03 +0000 | [diff] [blame] | 168 | func BazelLabelForModuleSrcSingle(ctx Bp2buildMutatorContext, path string) bazel.Label { |
Liz Kammer | daa09ef | 2021-12-15 15:35:38 -0500 | [diff] [blame] | 169 | if srcs := BazelLabelForModuleSrcExcludes(ctx, []string{path}, []string(nil)).Includes; len(srcs) > 0 { |
| 170 | return srcs[0] |
| 171 | } |
| 172 | return bazel.Label{} |
Lukacs T. Berki | 1353e59 | 2021-04-30 15:35:09 +0200 | [diff] [blame] | 173 | } |
| 174 | |
Chris Parsons | 5f1b3c7 | 2023-09-28 20:41:03 +0000 | [diff] [blame] | 175 | func BazelLabelForModuleDepSingle(ctx Bp2buildMutatorContext, path string) bazel.Label { |
Liz Kammer | daa09ef | 2021-12-15 15:35:38 -0500 | [diff] [blame] | 176 | if srcs := BazelLabelForModuleDepsExcludes(ctx, []string{path}, []string(nil)).Includes; len(srcs) > 0 { |
| 177 | return srcs[0] |
| 178 | } |
| 179 | return bazel.Label{} |
Rupert Shuttleworth | 6e4950a | 2021-07-27 01:34:59 -0400 | [diff] [blame] | 180 | } |
| 181 | |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 182 | // BazelLabelForModuleSrc expects a list of path (relative to local module directory) and module |
| 183 | // references (":<module>") and returns a bazel.LabelList{} containing the resolved references in |
| 184 | // paths, relative to the local module, or Bazel-labels (absolute if in a different package or |
| 185 | // relative if within the same package). |
| 186 | // Properties must have been annotated with struct tag `android:"path"` so that dependencies modules |
Spandan Das | 950091c | 2023-07-19 22:26:37 +0000 | [diff] [blame] | 187 | // will have already been handled by the pathdeps mutator. |
Chris Parsons | 5f1b3c7 | 2023-09-28 20:41:03 +0000 | [diff] [blame] | 188 | func BazelLabelForModuleSrc(ctx Bp2buildMutatorContext, paths []string) bazel.LabelList { |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 189 | return BazelLabelForModuleSrcExcludes(ctx, paths, []string(nil)) |
| 190 | } |
| 191 | |
| 192 | // BazelLabelForModuleSrc expects lists of path and excludes (relative to local module directory) |
| 193 | // and module references (":<module>") and returns a bazel.LabelList{} containing the resolved |
| 194 | // references in paths, minus those in excludes, relative to the local module, or Bazel-labels |
| 195 | // (absolute if in a different package or relative if within the same package). |
| 196 | // Properties must have been annotated with struct tag `android:"path"` so that dependencies modules |
Spandan Das | 950091c | 2023-07-19 22:26:37 +0000 | [diff] [blame] | 197 | // will have already been handled by the pathdeps mutator. |
Chris Parsons | 5f1b3c7 | 2023-09-28 20:41:03 +0000 | [diff] [blame] | 198 | func BazelLabelForModuleSrcExcludes(ctx Bp2buildMutatorContext, paths, excludes []string) bazel.LabelList { |
| 199 | excludeLabels := expandSrcsForBazel(ctx, excludes, []string(nil), false) |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 200 | excluded := make([]string, 0, len(excludeLabels.Includes)) |
| 201 | for _, e := range excludeLabels.Includes { |
| 202 | excluded = append(excluded, e.Label) |
| 203 | } |
Chris Parsons | 5f1b3c7 | 2023-09-28 20:41:03 +0000 | [diff] [blame] | 204 | labels := expandSrcsForBazel(ctx, paths, excluded, true) |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 205 | labels.Excludes = excludeLabels.Includes |
Spandan Das | 0a8a275 | 2023-06-21 01:50:33 +0000 | [diff] [blame] | 206 | labels = TransformSubpackagePaths(ctx.Config(), ctx.ModuleDir(), labels) |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 207 | return labels |
| 208 | } |
| 209 | |
Spandan Das | 0301066 | 2023-08-15 22:06:41 +0000 | [diff] [blame] | 210 | func BazelLabelForSrcPatternExcludes(ctx BazelConversionPathContext, dir, pattern string, excludes []string) bazel.LabelList { |
| 211 | topRelPaths, err := ctx.GlobWithDeps(filepath.Join(dir, pattern), excludes) |
| 212 | if err != nil { |
| 213 | ctx.ModuleErrorf("Could not search dir: %s for pattern %s due to %v\n", dir, pattern, err) |
| 214 | } |
| 215 | // An intermediate list of labels relative to `dir` that assumes that there no subpacakges beneath `dir` |
| 216 | dirRelLabels := []bazel.Label{} |
| 217 | for _, topRelPath := range topRelPaths { |
| 218 | dirRelPath := Rel(ctx, dir, topRelPath) |
| 219 | dirRelLabels = append(dirRelLabels, bazel.Label{Label: "./" + dirRelPath}) |
| 220 | } |
| 221 | // Return the package boudary resolved labels |
| 222 | return TransformSubpackagePaths(ctx.Config(), dir, bazel.MakeLabelList(dirRelLabels)) |
| 223 | } |
| 224 | |
Jingwen Chen | 0eeaeb8 | 2022-09-21 10:27:42 +0000 | [diff] [blame] | 225 | // Returns true if a prefix + components[:i] is a package boundary. |
| 226 | // |
| 227 | // A package boundary is determined by a BUILD file in the directory. This can happen in 2 cases: |
| 228 | // |
Usta Shrestha | d558031 | 2022-09-23 16:46:38 -0400 | [diff] [blame] | 229 | // 1. An Android.bp exists, which bp2build will always convert to a sibling BUILD file. |
| 230 | // 2. An Android.bp doesn't exist, but a checked-in BUILD/BUILD.bazel file exists, and that file |
| 231 | // is allowlisted by the bp2build configuration to be merged into the symlink forest workspace. |
Jingwen Chen | 0eeaeb8 | 2022-09-21 10:27:42 +0000 | [diff] [blame] | 232 | func isPackageBoundary(config Config, prefix string, components []string, componentIndex int) bool { |
Spandan Das | dc7d7f7 | 2023-09-28 21:23:30 +0000 | [diff] [blame] | 233 | isSymlink := func(c Config, path string) bool { |
| 234 | f, err := c.fs.Lstat(path) |
| 235 | if err != nil { |
| 236 | // The file does not exist |
| 237 | return false |
| 238 | } |
| 239 | return f.Mode()&os.ModeSymlink == os.ModeSymlink |
| 240 | } |
Jingwen Chen | 0eeaeb8 | 2022-09-21 10:27:42 +0000 | [diff] [blame] | 241 | prefix = filepath.Join(prefix, filepath.Join(components[:componentIndex+1]...)) |
| 242 | if exists, _, _ := config.fs.Exists(filepath.Join(prefix, "Android.bp")); exists { |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 243 | return true |
Spandan Das | dc7d7f7 | 2023-09-28 21:23:30 +0000 | [diff] [blame] | 244 | } else if config.Bp2buildPackageConfig.ShouldKeepExistingBuildFileForDir(prefix) || isSymlink(config, prefix) { |
Jingwen Chen | 0eeaeb8 | 2022-09-21 10:27:42 +0000 | [diff] [blame] | 245 | if exists, _, _ := config.fs.Exists(filepath.Join(prefix, "BUILD")); exists { |
| 246 | return true |
| 247 | } else if exists, _, _ := config.fs.Exists(filepath.Join(prefix, "BUILD.bazel")); exists { |
| 248 | return true |
| 249 | } |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 250 | } |
Jingwen Chen | 0eeaeb8 | 2022-09-21 10:27:42 +0000 | [diff] [blame] | 251 | |
| 252 | return false |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 253 | } |
| 254 | |
| 255 | // Transform a path (if necessary) to acknowledge package boundaries |
| 256 | // |
| 257 | // e.g. something like |
Colin Cross | d079e0b | 2022-08-16 10:27:33 -0700 | [diff] [blame] | 258 | // |
| 259 | // async_safe/include/async_safe/CHECK.h |
| 260 | // |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 261 | // might become |
Colin Cross | d079e0b | 2022-08-16 10:27:33 -0700 | [diff] [blame] | 262 | // |
| 263 | // //bionic/libc/async_safe:include/async_safe/CHECK.h |
| 264 | // |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 265 | // if the "async_safe" directory is actually a package and not just a directory. |
| 266 | // |
| 267 | // In particular, paths that extend into packages are transformed into absolute labels beginning with //. |
Spandan Das | 0a8a275 | 2023-06-21 01:50:33 +0000 | [diff] [blame] | 268 | func transformSubpackagePath(cfg Config, dir string, path bazel.Label) bazel.Label { |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 269 | var newPath bazel.Label |
| 270 | |
Jingwen Chen | 38e6264 | 2021-04-19 05:00:15 +0000 | [diff] [blame] | 271 | // Don't transform OriginalModuleName |
| 272 | newPath.OriginalModuleName = path.OriginalModuleName |
Liz Kammer | 1e75324 | 2023-06-02 19:03:06 -0400 | [diff] [blame] | 273 | // if it wasn't a module, store the original path. We may need the original path to replace |
| 274 | // references if it is actually in another package |
| 275 | if path.OriginalModuleName == "" { |
| 276 | newPath.OriginalModuleName = path.Label |
| 277 | } |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 278 | |
| 279 | if strings.HasPrefix(path.Label, "//") { |
| 280 | // Assume absolute labels are already correct (e.g. //path/to/some/package:foo.h) |
| 281 | newPath.Label = path.Label |
| 282 | return newPath |
| 283 | } |
Usta Shrestha | d558031 | 2022-09-23 16:46:38 -0400 | [diff] [blame] | 284 | if strings.HasPrefix(path.Label, "./") { |
| 285 | // Drop "./" for consistent handling of paths. |
| 286 | // Specifically, to not let "." be considered a package boundary. |
| 287 | // Say `inputPath` is `x/Android.bp` and that file has some module |
| 288 | // with `srcs=["y/a.c", "z/b.c"]`. |
| 289 | // And say the directory tree is: |
| 290 | // x |
| 291 | // ├── Android.bp |
| 292 | // ├── y |
| 293 | // │ ├── a.c |
| 294 | // │ └── Android.bp |
| 295 | // └── z |
| 296 | // └── b.c |
| 297 | // Then bazel equivalent labels in srcs should be: |
| 298 | // //x/y:a.c, x/z/b.c |
| 299 | // The above should still be the case if `x/Android.bp` had |
| 300 | // srcs=["./y/a.c", "./z/b.c"] |
| 301 | // However, if we didn't strip "./", we'd get |
| 302 | // //x/./y:a.c, //x/.:z/b.c |
| 303 | path.Label = strings.TrimPrefix(path.Label, "./") |
| 304 | } |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 305 | pathComponents := strings.Split(path.Label, "/") |
Usta Shrestha | d558031 | 2022-09-23 16:46:38 -0400 | [diff] [blame] | 306 | newLabel := "" |
Jingwen Chen | 0eeaeb8 | 2022-09-21 10:27:42 +0000 | [diff] [blame] | 307 | foundPackageBoundary := false |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 308 | // Check the deepest subdirectory first and work upwards |
| 309 | for i := len(pathComponents) - 1; i >= 0; i-- { |
| 310 | pathComponent := pathComponents[i] |
| 311 | var sep string |
Spandan Das | 0a8a275 | 2023-06-21 01:50:33 +0000 | [diff] [blame] | 312 | if !foundPackageBoundary && isPackageBoundary(cfg, dir, pathComponents, i) { |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 313 | sep = ":" |
Jingwen Chen | 0eeaeb8 | 2022-09-21 10:27:42 +0000 | [diff] [blame] | 314 | foundPackageBoundary = true |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 315 | } else { |
| 316 | sep = "/" |
| 317 | } |
| 318 | if newLabel == "" { |
| 319 | newLabel = pathComponent |
| 320 | } else { |
| 321 | newLabel = pathComponent + sep + newLabel |
| 322 | } |
| 323 | } |
Jingwen Chen | 0eeaeb8 | 2022-09-21 10:27:42 +0000 | [diff] [blame] | 324 | if foundPackageBoundary { |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 325 | // Ensure paths end up looking like //bionic/... instead of //./bionic/... |
Spandan Das | 0a8a275 | 2023-06-21 01:50:33 +0000 | [diff] [blame] | 326 | moduleDir := dir |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 327 | if strings.HasPrefix(moduleDir, ".") { |
| 328 | moduleDir = moduleDir[1:] |
| 329 | } |
| 330 | // Make the path into an absolute label (e.g. //bionic/libc/foo:bar.h instead of just foo:bar.h) |
| 331 | if moduleDir == "" { |
| 332 | newLabel = "//" + newLabel |
| 333 | } else { |
| 334 | newLabel = "//" + moduleDir + "/" + newLabel |
| 335 | } |
| 336 | } |
| 337 | newPath.Label = newLabel |
| 338 | |
| 339 | return newPath |
| 340 | } |
| 341 | |
| 342 | // Transform paths to acknowledge package boundaries |
| 343 | // See transformSubpackagePath() for more information |
Spandan Das | 0a8a275 | 2023-06-21 01:50:33 +0000 | [diff] [blame] | 344 | func TransformSubpackagePaths(cfg Config, dir string, paths bazel.LabelList) bazel.LabelList { |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 345 | var newPaths bazel.LabelList |
| 346 | for _, include := range paths.Includes { |
Spandan Das | 0a8a275 | 2023-06-21 01:50:33 +0000 | [diff] [blame] | 347 | newPaths.Includes = append(newPaths.Includes, transformSubpackagePath(cfg, dir, include)) |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 348 | } |
| 349 | for _, exclude := range paths.Excludes { |
Spandan Das | 0a8a275 | 2023-06-21 01:50:33 +0000 | [diff] [blame] | 350 | newPaths.Excludes = append(newPaths.Excludes, transformSubpackagePath(cfg, dir, exclude)) |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 351 | } |
| 352 | return newPaths |
| 353 | } |
| 354 | |
Romain Jobredeaux | 1282c42 | 2021-10-29 10:52:59 -0400 | [diff] [blame] | 355 | // Converts root-relative Paths to a list of bazel.Label relative to the module in ctx. |
| 356 | func RootToModuleRelativePaths(ctx BazelConversionPathContext, paths Paths) []bazel.Label { |
| 357 | var newPaths []bazel.Label |
| 358 | for _, path := range PathsWithModuleSrcSubDir(ctx, paths, "") { |
| 359 | s := path.Rel() |
| 360 | newPaths = append(newPaths, bazel.Label{Label: s}) |
| 361 | } |
| 362 | return newPaths |
| 363 | } |
| 364 | |
Chris Parsons | 5f1b3c7 | 2023-09-28 20:41:03 +0000 | [diff] [blame] | 365 | var Bp2buildDepTag bp2buildDepTag |
| 366 | |
| 367 | type bp2buildDepTag struct { |
| 368 | blueprint.BaseDependencyTag |
| 369 | } |
| 370 | |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 371 | // expandSrcsForBazel returns bazel.LabelList with paths rooted from the module's local source |
| 372 | // directory and Bazel target labels, excluding those included in the excludes argument (which |
| 373 | // should already be expanded to resolve references to Soong-modules). Valid elements of paths |
| 374 | // include: |
Colin Cross | d079e0b | 2022-08-16 10:27:33 -0700 | [diff] [blame] | 375 | // - filepath, relative to local module directory, resolves as a filepath relative to the local |
| 376 | // source directory |
| 377 | // - glob, relative to the local module directory, resolves as filepath(s), relative to the local |
| 378 | // module directory. Because Soong does not have a concept of crossing package boundaries, the |
| 379 | // glob as computed by Soong may contain paths that cross package-boundaries that would be |
| 380 | // unknowingly omitted if the glob were handled by Bazel. To allow identification and detect |
| 381 | // (within Bazel) use of paths that cross package boundaries, we expand globs within Soong rather |
| 382 | // than converting Soong glob syntax to Bazel glob syntax. **Invalid for excludes.** |
| 383 | // - other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer |
| 384 | // or OutputFileProducer. These resolve as a Bazel label for a target. If the Bazel target is in |
| 385 | // the local module directory, it will be returned relative to the current package (e.g. |
| 386 | // ":<target>"). Otherwise, it will be returned as an absolute Bazel label (e.g. |
| 387 | // "//path/to/dir:<target>"). If the reference to another module cannot be resolved,the function |
| 388 | // will panic. |
| 389 | // |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 390 | // Properties passed as the paths or excludes argument must have been annotated with struct tag |
| 391 | // `android:"path"` so that dependencies on other modules will have already been handled by the |
Spandan Das | 950091c | 2023-07-19 22:26:37 +0000 | [diff] [blame] | 392 | // pathdeps mutator. |
Chris Parsons | 5f1b3c7 | 2023-09-28 20:41:03 +0000 | [diff] [blame] | 393 | func expandSrcsForBazel(ctx Bp2buildMutatorContext, paths, expandedExcludes []string, markAsDeps bool) bazel.LabelList { |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 394 | if paths == nil { |
| 395 | return bazel.LabelList{} |
| 396 | } |
| 397 | labels := bazel.LabelList{ |
| 398 | Includes: []bazel.Label{}, |
| 399 | } |
Jingwen Chen | 4ecc67d | 2021-04-27 09:47:02 +0000 | [diff] [blame] | 400 | |
| 401 | // expandedExcludes contain module-dir relative paths, but root-relative paths |
| 402 | // are needed for GlobFiles later. |
| 403 | var rootRelativeExpandedExcludes []string |
| 404 | for _, e := range expandedExcludes { |
| 405 | rootRelativeExpandedExcludes = append(rootRelativeExpandedExcludes, filepath.Join(ctx.ModuleDir(), e)) |
| 406 | } |
| 407 | |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 408 | for _, p := range paths { |
| 409 | if m, tag := SrcIsModuleWithTag(p); m != "" { |
Chris Parsons | 5f1b3c7 | 2023-09-28 20:41:03 +0000 | [diff] [blame] | 410 | l := getOtherModuleLabel(ctx, m, tag, BazelModuleLabel, markAsDeps) |
Liz Kammer | daa09ef | 2021-12-15 15:35:38 -0500 | [diff] [blame] | 411 | if l != nil && !InList(l.Label, expandedExcludes) { |
Spandan Das | f62e80a | 2023-08-17 22:35:04 +0000 | [diff] [blame] | 412 | if strings.HasPrefix(m, "//") { |
| 413 | // this is a module in a soong namespace |
| 414 | // It appears as //<namespace>:<module_name> in srcs, and not ://<namespace>:<module_name> |
| 415 | l.OriginalModuleName = m |
| 416 | } else { |
| 417 | l.OriginalModuleName = fmt.Sprintf(":%s", m) |
| 418 | } |
Liz Kammer | daa09ef | 2021-12-15 15:35:38 -0500 | [diff] [blame] | 419 | labels.Includes = append(labels.Includes, *l) |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 420 | } |
| 421 | } else { |
| 422 | var expandedPaths []bazel.Label |
| 423 | if pathtools.IsGlob(p) { |
Jingwen Chen | 4ecc67d | 2021-04-27 09:47:02 +0000 | [diff] [blame] | 424 | // e.g. turn "math/*.c" in |
| 425 | // external/arm-optimized-routines to external/arm-optimized-routines/math/*.c |
| 426 | rootRelativeGlobPath := pathForModuleSrc(ctx, p).String() |
Romain Jobredeaux | 1282c42 | 2021-10-29 10:52:59 -0400 | [diff] [blame] | 427 | expandedPaths = RootToModuleRelativePaths(ctx, GlobFiles(ctx, rootRelativeGlobPath, rootRelativeExpandedExcludes)) |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 428 | } else { |
| 429 | if !InList(p, expandedExcludes) { |
| 430 | expandedPaths = append(expandedPaths, bazel.Label{Label: p}) |
| 431 | } |
| 432 | } |
| 433 | labels.Includes = append(labels.Includes, expandedPaths...) |
| 434 | } |
| 435 | } |
| 436 | return labels |
| 437 | } |
| 438 | |
| 439 | // getOtherModuleLabel returns a bazel.Label for the given dependency/tag combination for the |
| 440 | // module. The label will be relative to the current directory if appropriate. The dependency must |
| 441 | // already be resolved by either deps mutator or path deps mutator. |
Chris Parsons | 5f1b3c7 | 2023-09-28 20:41:03 +0000 | [diff] [blame] | 442 | func getOtherModuleLabel(ctx Bp2buildMutatorContext, dep, tag string, |
| 443 | labelFromModule func(BazelConversionPathContext, blueprint.Module) string, |
| 444 | markAsDep bool) *bazel.Label { |
Chris Parsons | 5a34ffb | 2021-07-21 14:34:58 -0400 | [diff] [blame] | 445 | m, _ := ctx.ModuleFromName(dep) |
Liz Kammer | daa09ef | 2021-12-15 15:35:38 -0500 | [diff] [blame] | 446 | // The module was not found in an Android.bp file, this is often due to: |
| 447 | // * a limited manifest |
| 448 | // * a required module not being converted from Android.mk |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 449 | if m == nil { |
Liz Kammer | daa09ef | 2021-12-15 15:35:38 -0500 | [diff] [blame] | 450 | ctx.AddMissingBp2buildDep(dep) |
| 451 | return &bazel.Label{ |
| 452 | Label: ":" + dep + "__BP2BUILD__MISSING__DEP", |
| 453 | } |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 454 | } |
Chris Parsons | 44215bc | 2023-10-04 21:51:17 +0000 | [diff] [blame] | 455 | // Returns true if a dependency from the current module to the target module |
| 456 | // should be skipped; doing so is a hack to circumvent certain problematic |
| 457 | // scenarios that will be addressed in the future. |
| 458 | shouldSkipDep := func(dep string) bool { |
Chris Parsons | 5f1b3c7 | 2023-09-28 20:41:03 +0000 | [diff] [blame] | 459 | // Don't count dependencies of "libc". This is a hack to circumvent the |
| 460 | // fact that, in a variantless build graph, "libc" has a dependency on itself. |
Chris Parsons | 44215bc | 2023-10-04 21:51:17 +0000 | [diff] [blame] | 461 | if ctx.ModuleName() == "libc" { |
| 462 | return true |
Chris Parsons | 5f1b3c7 | 2023-09-28 20:41:03 +0000 | [diff] [blame] | 463 | } |
Chris Parsons | 44215bc | 2023-10-04 21:51:17 +0000 | [diff] [blame] | 464 | |
| 465 | // TODO: b/303307672: Dependencies on this module happen to "work" because |
| 466 | // there is a source file with the same name as this module in the |
| 467 | // same directory. We should remove this hack and enforce the underlying |
| 468 | // module of this name is the actual one used. |
| 469 | if dep == "mke2fs.conf" { |
| 470 | return true |
| 471 | } |
| 472 | |
| 473 | // TODO: b/303310285: Remove this special-casing once all dependencies of |
| 474 | // crtbegin_dynamic are convertible |
| 475 | if ctx.ModuleName() == "crtbegin_dynamic" { |
| 476 | return true |
| 477 | } |
| 478 | |
| 479 | return false |
| 480 | } |
| 481 | if markAsDep && !shouldSkipDep(dep) { |
| 482 | ctx.AddDependency(ctx.Module(), Bp2buildDepTag, dep) |
Chris Parsons | 5f1b3c7 | 2023-09-28 20:41:03 +0000 | [diff] [blame] | 483 | } |
Liz Kammer | 6eff323 | 2021-08-26 08:37:59 -0400 | [diff] [blame] | 484 | if !convertedToBazel(ctx, m) { |
| 485 | ctx.AddUnconvertedBp2buildDep(dep) |
| 486 | } |
Chris Parsons | 953b356 | 2021-09-20 15:14:39 -0400 | [diff] [blame] | 487 | label := BazelModuleLabel(ctx, ctx.Module()) |
| 488 | otherLabel := labelFromModule(ctx, m) |
| 489 | |
| 490 | // TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets. |
Yu Liu | f2b9401 | 2023-09-19 15:09:10 -0700 | [diff] [blame] | 491 | if (tag != "" && m.Name() == "framework-res") || |
| 492 | (tag == ".generated_srcjars" && ctx.OtherModuleType(m) == "java_aconfig_library") { |
Romain Jobredeaux | 9c06ef3 | 2023-08-21 18:05:29 -0400 | [diff] [blame] | 493 | otherLabel += tag |
| 494 | } |
Chris Parsons | 953b356 | 2021-09-20 15:14:39 -0400 | [diff] [blame] | 495 | |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 496 | if samePackage(label, otherLabel) { |
| 497 | otherLabel = bazelShortLabel(otherLabel) |
| 498 | } |
| 499 | |
Liz Kammer | daa09ef | 2021-12-15 15:35:38 -0500 | [diff] [blame] | 500 | return &bazel.Label{ |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 501 | Label: otherLabel, |
| 502 | } |
| 503 | } |
| 504 | |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame] | 505 | func BazelModuleLabel(ctx BazelConversionPathContext, module blueprint.Module) string { |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 506 | // TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets. |
Spandan Das | 6485242 | 2023-08-02 21:58:41 +0000 | [diff] [blame] | 507 | if !convertedToBazel(ctx, module) || isGoModule(module) { |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 508 | return bp2buildModuleLabel(ctx, module) |
| 509 | } |
Liz Kammer | 6eff323 | 2021-08-26 08:37:59 -0400 | [diff] [blame] | 510 | b, _ := module.(Bazelable) |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 511 | return b.GetBazelLabel(ctx, module) |
| 512 | } |
| 513 | |
| 514 | func bazelShortLabel(label string) string { |
| 515 | i := strings.Index(label, ":") |
Jingwen Chen | 80b6b64 | 2021-11-02 06:23:07 +0000 | [diff] [blame] | 516 | if i == -1 { |
| 517 | panic(fmt.Errorf("Could not find the ':' character in '%s', expected a fully qualified label.", label)) |
| 518 | } |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 519 | return label[i:] |
| 520 | } |
| 521 | |
| 522 | func bazelPackage(label string) string { |
| 523 | i := strings.Index(label, ":") |
Jingwen Chen | 80b6b64 | 2021-11-02 06:23:07 +0000 | [diff] [blame] | 524 | if i == -1 { |
| 525 | panic(fmt.Errorf("Could not find the ':' character in '%s', expected a fully qualified label.", label)) |
| 526 | } |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 527 | return label[0:i] |
| 528 | } |
| 529 | |
| 530 | func samePackage(label1, label2 string) bool { |
| 531 | return bazelPackage(label1) == bazelPackage(label2) |
| 532 | } |
| 533 | |
Jingwen Chen | 55bc820 | 2021-11-02 06:40:51 +0000 | [diff] [blame] | 534 | func bp2buildModuleLabel(ctx BazelConversionContext, module blueprint.Module) string { |
Liz Kammer | c86e094 | 2023-08-11 16:15:12 -0400 | [diff] [blame] | 535 | moduleName := moduleNameWithPossibleOverride(ctx, module, ctx.OtherModuleName(module)) |
| 536 | moduleDir := moduleDirWithPossibleOverride(ctx, module, ctx.OtherModuleDir(module)) |
Jingwen Chen | 889f2f2 | 2022-12-16 08:16:01 +0000 | [diff] [blame] | 537 | if moduleDir == Bp2BuildTopLevel { |
| 538 | moduleDir = "" |
| 539 | } |
Liz Kammer | e1b39a5 | 2023-09-18 14:32:18 -0400 | [diff] [blame] | 540 | if a, ok := module.(Module); ok && IsModulePrebuilt(a) { |
| 541 | moduleName = RemoveOptionalPrebuiltPrefix(moduleName) |
| 542 | } |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 543 | return fmt.Sprintf("//%s:%s", moduleDir, moduleName) |
| 544 | } |
| 545 | |
| 546 | // BazelOutPath is a Bazel output path compatible to be used for mixed builds within Soong/Ninja. |
| 547 | type BazelOutPath struct { |
| 548 | OutputPath |
| 549 | } |
| 550 | |
Liz Kammer | 0f3b7d2 | 2021-09-28 13:48:21 -0400 | [diff] [blame] | 551 | // ensure BazelOutPath implements Path |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 552 | var _ Path = BazelOutPath{} |
Liz Kammer | 0f3b7d2 | 2021-09-28 13:48:21 -0400 | [diff] [blame] | 553 | |
| 554 | // ensure BazelOutPath implements genPathProvider |
| 555 | var _ genPathProvider = BazelOutPath{} |
| 556 | |
| 557 | // ensure BazelOutPath implements objPathProvider |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 558 | var _ objPathProvider = BazelOutPath{} |
| 559 | |
Liz Kammer | 0f3b7d2 | 2021-09-28 13:48:21 -0400 | [diff] [blame] | 560 | func (p BazelOutPath) genPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleGenPath { |
| 561 | return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext)) |
| 562 | } |
| 563 | |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 564 | func (p BazelOutPath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath { |
| 565 | return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext)) |
| 566 | } |
| 567 | |
Cole Faust | 9a06d25 | 2022-06-03 16:00:11 -0700 | [diff] [blame] | 568 | // PathForBazelOutRelative returns a BazelOutPath representing the path under an output directory dedicated to |
| 569 | // bazel-owned outputs. Calling .Rel() on the result will give the input path as relative to the given |
| 570 | // relativeRoot. |
| 571 | func PathForBazelOutRelative(ctx PathContext, relativeRoot string, path string) BazelOutPath { |
| 572 | validatedPath, err := validatePath(filepath.Join("execroot", "__main__", path)) |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 573 | if err != nil { |
| 574 | reportPathError(ctx, err) |
| 575 | } |
Cole Faust | 0abd4b4 | 2023-01-10 10:49:18 -0800 | [diff] [blame] | 576 | var relativeRootPath string |
| 577 | if pathComponents := strings.SplitN(path, "/", 4); len(pathComponents) >= 3 && |
Cole Faust | 9a06d25 | 2022-06-03 16:00:11 -0700 | [diff] [blame] | 578 | pathComponents[0] == "bazel-out" && pathComponents[2] == "bin" { |
| 579 | // If the path starts with something like: bazel-out/linux_x86_64-fastbuild-ST-b4ef1c4402f9/bin/ |
| 580 | // make it relative to that folder. bazel-out/volatile-status.txt is an example |
| 581 | // of something that starts with bazel-out but is not relative to the bin folder |
| 582 | relativeRootPath = filepath.Join("execroot", "__main__", pathComponents[0], pathComponents[1], pathComponents[2], relativeRoot) |
Cole Faust | 0abd4b4 | 2023-01-10 10:49:18 -0800 | [diff] [blame] | 583 | } else { |
| 584 | relativeRootPath = filepath.Join("execroot", "__main__", relativeRoot) |
Cole Faust | 9a06d25 | 2022-06-03 16:00:11 -0700 | [diff] [blame] | 585 | } |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 586 | |
Cole Faust | 9a06d25 | 2022-06-03 16:00:11 -0700 | [diff] [blame] | 587 | var relPath string |
| 588 | if relPath, err = filepath.Rel(relativeRootPath, validatedPath); err != nil || strings.HasPrefix(relPath, "../") { |
| 589 | // We failed to make this path relative to execroot/__main__, fall back to a non-relative path |
| 590 | // One case where this happens is when path is ../bazel_tools/something |
| 591 | relativeRootPath = "" |
| 592 | relPath = validatedPath |
| 593 | } |
| 594 | |
| 595 | outputPath := OutputPath{ |
| 596 | basePath{"", ""}, |
Lukacs T. Berki | 9f6c24a | 2021-08-26 15:07:24 +0200 | [diff] [blame] | 597 | ctx.Config().soongOutDir, |
Cole Faust | 9a06d25 | 2022-06-03 16:00:11 -0700 | [diff] [blame] | 598 | ctx.Config().BazelContext.OutputBase(), |
| 599 | } |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 600 | |
| 601 | return BazelOutPath{ |
Cole Faust | 9a06d25 | 2022-06-03 16:00:11 -0700 | [diff] [blame] | 602 | // .withRel() appends its argument onto the current path, and only the most |
| 603 | // recently appended part is returned by outputPath.rel(). |
| 604 | // So outputPath.rel() will return relPath. |
| 605 | OutputPath: outputPath.withRel(relativeRootPath).withRel(relPath), |
Liz Kammer | 620dea6 | 2021-04-14 17:36:10 -0400 | [diff] [blame] | 606 | } |
| 607 | } |
Liz Kammer | b6a55bf | 2021-04-12 15:42:51 -0400 | [diff] [blame] | 608 | |
Cole Faust | 9a06d25 | 2022-06-03 16:00:11 -0700 | [diff] [blame] | 609 | // PathForBazelOut returns a BazelOutPath representing the path under an output directory dedicated to |
| 610 | // bazel-owned outputs. |
| 611 | func PathForBazelOut(ctx PathContext, path string) BazelOutPath { |
| 612 | return PathForBazelOutRelative(ctx, "", path) |
| 613 | } |
| 614 | |
Liz Kammer | b6a55bf | 2021-04-12 15:42:51 -0400 | [diff] [blame] | 615 | // PathsForBazelOut returns a list of paths representing the paths under an output directory |
| 616 | // dedicated to Bazel-owned outputs. |
| 617 | func PathsForBazelOut(ctx PathContext, paths []string) Paths { |
| 618 | outs := make(Paths, 0, len(paths)) |
| 619 | for _, p := range paths { |
| 620 | outs = append(outs, PathForBazelOut(ctx, p)) |
| 621 | } |
| 622 | return outs |
| 623 | } |
Jingwen Chen | 6817bbb | 2022-10-14 09:56:07 +0000 | [diff] [blame] | 624 | |
| 625 | // BazelStringOrLabelFromProp splits a Soong module property that can be |
| 626 | // either a string literal, path (with android:path tag) or a module reference |
| 627 | // into separate bazel string or label attributes. Bazel treats string and label |
| 628 | // attributes as distinct types, so this function categorizes a string property |
| 629 | // into either one of them. |
| 630 | // |
| 631 | // e.g. apex.private_key = "foo.pem" can either refer to: |
| 632 | // |
| 633 | // 1. "foo.pem" in the current directory -> file target |
| 634 | // 2. "foo.pem" module -> rule target |
| 635 | // 3. "foo.pem" file in a different directory, prefixed by a product variable handled |
| 636 | // in a bazel macro. -> string literal |
| 637 | // |
| 638 | // For the first two cases, they are defined using the label attribute. For the third case, |
| 639 | // it's defined with the string attribute. |
| 640 | func BazelStringOrLabelFromProp( |
Chris Parsons | 637458d | 2023-09-19 20:09:00 +0000 | [diff] [blame] | 641 | ctx Bp2buildMutatorContext, |
Jingwen Chen | 6817bbb | 2022-10-14 09:56:07 +0000 | [diff] [blame] | 642 | propToDistinguish *string) (bazel.LabelAttribute, bazel.StringAttribute) { |
| 643 | |
| 644 | var labelAttr bazel.LabelAttribute |
| 645 | var strAttr bazel.StringAttribute |
| 646 | |
| 647 | if propToDistinguish == nil { |
| 648 | // nil pointer |
| 649 | return labelAttr, strAttr |
| 650 | } |
| 651 | |
| 652 | prop := String(propToDistinguish) |
| 653 | if SrcIsModule(prop) != "" { |
| 654 | // If it's a module (SrcIsModule will return the module name), set the |
| 655 | // resolved label to the label attribute. |
| 656 | labelAttr.SetValue(BazelLabelForModuleDepSingle(ctx, prop)) |
| 657 | } else { |
| 658 | // Not a module name. This could be a string literal or a file target in |
| 659 | // the current dir. Check if the path exists: |
| 660 | path := ExistentPathForSource(ctx, ctx.ModuleDir(), prop) |
| 661 | |
| 662 | if path.Valid() && parentDir(path.String()) == ctx.ModuleDir() { |
| 663 | // If it exists and the path is relative to the current dir, resolve the bazel label |
| 664 | // for the _file target_ and set it to the label attribute. |
| 665 | // |
| 666 | // Resolution is necessary because this could be a file in a subpackage. |
| 667 | labelAttr.SetValue(BazelLabelForModuleSrcSingle(ctx, prop)) |
| 668 | } else { |
| 669 | // Otherwise, treat it as a string literal and assign to the string attribute. |
| 670 | strAttr.Value = propToDistinguish |
| 671 | } |
| 672 | } |
| 673 | |
| 674 | return labelAttr, strAttr |
| 675 | } |