blob: 6cc9232b69654673a46eb307c8f2370e3028762b [file] [log] [blame]
Colin Cross068e0fe2016-12-13 15:23:47 -08001// Copyright 2016 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
Pirama Arumuga Nainar955dc492018-04-17 14:58:42 -070015package android
Colin Cross068e0fe2016-12-13 15:23:47 -080016
17import (
Vinh Tran16fe8e12022-08-16 16:45:44 -040018 "path/filepath"
Sam Delmerico97bd1272022-08-25 14:45:31 -040019 "regexp"
Colin Crossd91d7ac2017-09-12 22:52:12 -070020 "strings"
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux0d990452021-08-11 16:46:13 +000021
22 "android/soong/bazel"
Chris Parsonsf874e462022-05-10 13:50:12 -040023 "android/soong/bazel/cquery"
Chris Parsons39a16972023-06-08 14:28:51 +000024 "android/soong/ui/metrics/bp2build_metrics_proto"
Sam Delmericoc7681022022-02-04 21:01:20 +000025
26 "github.com/google/blueprint"
Spandan Dasdf3ec822023-08-04 02:19:53 +000027 "github.com/google/blueprint/proptools"
Colin Cross068e0fe2016-12-13 15:23:47 -080028)
29
30func init() {
Anton Hansson7d6dd8b2023-03-06 11:26:17 +000031 RegisterFilegroupBuildComponents(InitRegistrationContext)
Jingwen Chen32b4ece2021-01-21 03:20:18 -050032}
33
Paul Duffin35816122021-02-24 01:49:52 +000034var PrepareForTestWithFilegroup = FixtureRegisterWithContext(func(ctx RegistrationContext) {
Anton Hansson7d6dd8b2023-03-06 11:26:17 +000035 RegisterFilegroupBuildComponents(ctx)
Paul Duffin35816122021-02-24 01:49:52 +000036})
37
Anton Hansson7d6dd8b2023-03-06 11:26:17 +000038func RegisterFilegroupBuildComponents(ctx RegistrationContext) {
39 ctx.RegisterModuleType("filegroup", FileGroupFactory)
40 ctx.RegisterModuleType("filegroup_defaults", FileGroupDefaultsFactory)
41}
42
Yu Liu2aa806b2022-09-01 11:54:47 -070043var convertedProtoLibrarySuffix = "_bp2build_converted"
44
Sam Delmericoc7681022022-02-04 21:01:20 +000045// IsFilegroup checks that a module is a filegroup type
46func IsFilegroup(ctx bazel.OtherModuleContext, m blueprint.Module) bool {
47 return ctx.OtherModuleType(m) == "filegroup"
48}
49
Sam Delmerico97bd1272022-08-25 14:45:31 -040050var (
51 // ignoring case, checks for proto or protos as an independent word in the name, whether at the
52 // beginning, end, or middle. e.g. "proto.foo", "bar-protos", "baz_proto_srcs" would all match
53 filegroupLikelyProtoPattern = regexp.MustCompile("(?i)(^|[^a-z])proto(s)?([^a-z]|$)")
54 filegroupLikelyAidlPattern = regexp.MustCompile("(?i)(^|[^a-z])aidl([^a-z]|$)")
55
56 ProtoSrcLabelPartition = bazel.LabelPartition{
57 Extensions: []string{".proto"},
58 LabelMapper: isFilegroupWithPattern(filegroupLikelyProtoPattern),
59 }
60 AidlSrcLabelPartition = bazel.LabelPartition{
61 Extensions: []string{".aidl"},
62 LabelMapper: isFilegroupWithPattern(filegroupLikelyAidlPattern),
63 }
64)
65
66func isFilegroupWithPattern(pattern *regexp.Regexp) bazel.LabelMapper {
67 return func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
68 m, exists := ctx.ModuleFromName(label.OriginalModuleName)
69 labelStr := label.Label
70 if !exists || !IsFilegroup(ctx, m) {
71 return labelStr, false
72 }
73 likelyMatched := pattern.MatchString(label.OriginalModuleName)
74 return labelStr, likelyMatched
75 }
76}
77
Jingwen Chen32b4ece2021-01-21 03:20:18 -050078// https://docs.bazel.build/versions/master/be/general.html#filegroup
79type bazelFilegroupAttributes struct {
Wei Li2c9e8d62023-05-05 01:07:15 -070080 Srcs bazel.LabelListAttribute
81 Applicable_licenses bazel.LabelListAttribute
Jingwen Chen32b4ece2021-01-21 03:20:18 -050082}
83
Vinh Tran444154d2022-08-16 13:10:31 -040084type bazelAidlLibraryAttributes struct {
85 Srcs bazel.LabelListAttribute
86 Strip_import_prefix *string
87}
88
Spandan Dasbd52ea92023-03-09 23:03:07 +000089// api srcs can be contained in filegroups.
90// this should be generated in api_bp2build workspace as well.
91func (fg *fileGroup) ConvertWithApiBp2build(ctx TopDownMutatorContext) {
92 fg.ConvertWithBp2build(ctx)
93}
94
Liz Kammerbe46fcc2021-11-01 15:32:43 -040095// ConvertWithBp2build performs bp2build conversion of filegroup
96func (fg *fileGroup) ConvertWithBp2build(ctx TopDownMutatorContext) {
Jingwen Chen07027912021-03-15 06:02:43 -040097 srcs := bazel.MakeLabelListAttribute(
98 BazelLabelForModuleSrcExcludes(ctx, fg.properties.Srcs, fg.properties.Exclude_srcs))
Jingwen Chen5146ac02021-09-02 11:44:42 +000099
100 // For Bazel compatibility, don't generate the filegroup if there is only 1
101 // source file, and that the source file is named the same as the module
102 // itself. In Bazel, eponymous filegroups like this would be an error.
103 //
104 // Instead, dependents on this single-file filegroup can just depend
105 // on the file target, instead of rule target, directly.
106 //
107 // You may ask: what if a filegroup has multiple files, and one of them
108 // shares the name? The answer: we haven't seen that in the wild, and
109 // should lock Soong itself down to prevent the behavior. For now,
110 // we raise an error if bp2build sees this problem.
111 for _, f := range srcs.Value.Includes {
112 if f.Label == fg.Name() {
113 if len(srcs.Value.Includes) > 1 {
114 ctx.ModuleErrorf("filegroup '%s' cannot contain a file with the same name", fg.Name())
115 }
Chris Parsons39a16972023-06-08 14:28:51 +0000116 ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_SRC_NAME_COLLISION, "")
Jingwen Chen5146ac02021-09-02 11:44:42 +0000117 return
118 }
119 }
120
Vinh Tran444154d2022-08-16 13:10:31 -0400121 // Convert module that has only AIDL files to aidl_library
122 // If the module has a mixed bag of AIDL and non-AIDL files, split the filegroup manually
123 // and then convert
124 if fg.ShouldConvertToAidlLibrary(ctx) {
Liz Kammer2b3f56e2023-03-23 11:51:49 -0400125 tags := []string{"apex_available=//apex_available:anyapex"}
Vinh Tran444154d2022-08-16 13:10:31 -0400126 attrs := &bazelAidlLibraryAttributes{
127 Srcs: srcs,
128 Strip_import_prefix: fg.properties.Path,
129 }
Jingwen Chen1fd14692021-02-05 03:01:50 -0500130
Vinh Tran444154d2022-08-16 13:10:31 -0400131 props := bazel.BazelTargetModuleProperties{
132 Rule_class: "aidl_library",
Sam Delmericoe55bf082023-03-31 09:47:28 -0400133 Bzl_load_location: "//build/bazel/rules/aidl:aidl_library.bzl",
Vinh Tran444154d2022-08-16 13:10:31 -0400134 }
Jingwen Chen1fd14692021-02-05 03:01:50 -0500135
Liz Kammer2b3f56e2023-03-23 11:51:49 -0400136 ctx.CreateBazelTargetModule(
137 props,
138 CommonAttributes{
139 Name: fg.Name(),
140 Tags: bazel.MakeStringListAttribute(tags),
141 },
142 attrs)
Vinh Tran444154d2022-08-16 13:10:31 -0400143 } else {
Yu Liu2aa806b2022-09-01 11:54:47 -0700144 if fg.ShouldConvertToProtoLibrary(ctx) {
Spandan Dasdf3ec822023-08-04 02:19:53 +0000145 pkgToSrcs := partitionSrcsByPackage(ctx.ModuleDir(), bazel.MakeLabelList(srcs.Value.Includes))
146 if len(pkgToSrcs) > 1 {
147 ctx.ModuleErrorf("TODO: Add bp2build support for multiple package .protosrcs in filegroup")
148 return
149 }
150 pkg := SortedKeys(pkgToSrcs)[0]
Yu Liu2aa806b2022-09-01 11:54:47 -0700151 attrs := &ProtoAttrs{
Spandan Dasdf3ec822023-08-04 02:19:53 +0000152 Srcs: bazel.MakeLabelListAttribute(pkgToSrcs[pkg]),
Yu Liu2aa806b2022-09-01 11:54:47 -0700153 Strip_import_prefix: fg.properties.Path,
154 }
155
Liz Kammer2b3f56e2023-03-23 11:51:49 -0400156 tags := []string{
157 "apex_available=//apex_available:anyapex",
158 // TODO(b/246997908): we can remove this tag if we could figure out a solution for this bug.
159 "manual",
160 }
Spandan Dasdf3ec822023-08-04 02:19:53 +0000161 if pkg != ctx.ModuleDir() {
162 // Since we are creating the proto_library in a subpackage, create an import_prefix relative to the current package
163 if rel, err := filepath.Rel(ctx.ModuleDir(), pkg); err != nil {
164 ctx.ModuleErrorf("Could not get relative path for %v %v", pkg, err)
165 } else if rel != "." {
166 attrs.Import_prefix = &rel
167 // Strip the package prefix
168 attrs.Strip_import_prefix = proptools.StringPtr("")
169 }
170 }
171
Yu Liu2aa806b2022-09-01 11:54:47 -0700172 ctx.CreateBazelTargetModule(
173 bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
Sam Delmericoe9b33f72022-11-21 15:38:54 -0500174 CommonAttributes{
Spandan Dasdf3ec822023-08-04 02:19:53 +0000175 Name: fg.Name() + "_proto",
176 Dir: proptools.StringPtr(pkg),
Sam Delmericoe9b33f72022-11-21 15:38:54 -0500177 Tags: bazel.MakeStringListAttribute(tags),
178 },
Yu Liu2aa806b2022-09-01 11:54:47 -0700179 attrs)
Spandan Dasdf3ec822023-08-04 02:19:53 +0000180
181 // Create an alias in the current dir. The actual target might exist in a different package, but rdeps
182 // can reliabily use this alias
183 ctx.CreateBazelTargetModule(
184 bazel.BazelTargetModuleProperties{Rule_class: "alias"},
185 CommonAttributes{
186 Name: fg.Name() + convertedProtoLibrarySuffix,
187 // TODO(b/246997908): we can remove this tag if we could figure out a solution for this bug.
188 Tags: bazel.MakeStringListAttribute(tags),
189 },
190 &bazelAliasAttributes{
191 Actual: bazel.MakeLabelAttribute("//" + pkg + ":" + fg.Name() + "_proto"),
192 },
193 )
Yu Liu2aa806b2022-09-01 11:54:47 -0700194 }
195
196 // TODO(b/242847534): Still convert to a filegroup because other unconverted
197 // modules may depend on the filegroup
Vinh Tran444154d2022-08-16 13:10:31 -0400198 attrs := &bazelFilegroupAttributes{
199 Srcs: srcs,
200 }
201
202 props := bazel.BazelTargetModuleProperties{
203 Rule_class: "filegroup",
204 Bzl_load_location: "//build/bazel/rules:filegroup.bzl",
205 }
206
207 ctx.CreateBazelTargetModule(props, CommonAttributes{Name: fg.Name()}, attrs)
208 }
Colin Cross068e0fe2016-12-13 15:23:47 -0800209}
210
Alixb29a3cd2023-05-09 20:37:49 +0000211type FileGroupPath interface {
212 GetPath(ctx TopDownMutatorContext) string
213}
214
215func (fg *fileGroup) GetPath(ctx TopDownMutatorContext) string {
216 if fg.properties.Path != nil {
217 return *fg.properties.Path
218 }
219 return ""
220}
221
Colin Cross068e0fe2016-12-13 15:23:47 -0800222type fileGroupProperties struct {
223 // srcs lists files that will be included in this filegroup
Colin Cross27b922f2019-03-04 22:35:41 -0800224 Srcs []string `android:"path"`
Colin Cross068e0fe2016-12-13 15:23:47 -0800225
Colin Cross27b922f2019-03-04 22:35:41 -0800226 Exclude_srcs []string `android:"path"`
Colin Crossfaeb7aa2017-02-01 14:12:44 -0800227
228 // The base path to the files. May be used by other modules to determine which portion
229 // of the path to use. For example, when a filegroup is used as data in a cc_test rule,
230 // the base path is stripped off the path and the remaining path is used as the
231 // installation directory.
Nan Zhangea568a42017-11-08 21:20:04 -0800232 Path *string
Colin Crossd91d7ac2017-09-12 22:52:12 -0700233
234 // Create a make variable with the specified name that contains the list of files in the
235 // filegroup, relative to the root of the source tree.
Nan Zhangea568a42017-11-08 21:20:04 -0800236 Export_to_make_var *string
Colin Cross068e0fe2016-12-13 15:23:47 -0800237}
238
239type fileGroup struct {
Pirama Arumuga Nainar955dc492018-04-17 14:58:42 -0700240 ModuleBase
Liz Kammerea6666f2021-02-17 10:17:28 -0500241 BazelModuleBase
Anton Hansson7d6dd8b2023-03-06 11:26:17 +0000242 DefaultableModuleBase
Yu Liu2aa806b2022-09-01 11:54:47 -0700243 FileGroupAsLibrary
Alixb29a3cd2023-05-09 20:37:49 +0000244 FileGroupPath
Colin Cross068e0fe2016-12-13 15:23:47 -0800245 properties fileGroupProperties
Pirama Arumuga Nainar955dc492018-04-17 14:58:42 -0700246 srcs Paths
Colin Cross068e0fe2016-12-13 15:23:47 -0800247}
248
Chris Parsonsf874e462022-05-10 13:50:12 -0400249var _ MixedBuildBuildable = (*fileGroup)(nil)
Pirama Arumuga Nainar955dc492018-04-17 14:58:42 -0700250var _ SourceFileProducer = (*fileGroup)(nil)
Yu Liu2aa806b2022-09-01 11:54:47 -0700251var _ FileGroupAsLibrary = (*fileGroup)(nil)
Alixb29a3cd2023-05-09 20:37:49 +0000252var _ FileGroupPath = (*fileGroup)(nil)
Colin Cross068e0fe2016-12-13 15:23:47 -0800253
Patrice Arruda8958a942019-03-12 10:06:00 -0700254// filegroup contains a list of files that are referenced by other modules
255// properties (such as "srcs") using the syntax ":<name>". filegroup are
256// also be used to export files across package boundaries.
Pirama Arumuga Nainar955dc492018-04-17 14:58:42 -0700257func FileGroupFactory() Module {
Colin Cross068e0fe2016-12-13 15:23:47 -0800258 module := &fileGroup{}
Colin Cross36242852017-06-23 15:06:31 -0700259 module.AddProperties(&module.properties)
Pirama Arumuga Nainar955dc492018-04-17 14:58:42 -0700260 InitAndroidModule(module)
Liz Kammerea6666f2021-02-17 10:17:28 -0500261 InitBazelModule(module)
Anton Hansson7d6dd8b2023-03-06 11:26:17 +0000262 InitDefaultableModule(module)
Colin Cross36242852017-06-23 15:06:31 -0700263 return module
Colin Cross068e0fe2016-12-13 15:23:47 -0800264}
265
Liz Kammer5edc1412022-05-25 11:12:44 -0400266var _ blueprint.JSONActionSupplier = (*fileGroup)(nil)
267
268func (fg *fileGroup) JSONActions() []blueprint.JSONAction {
269 ins := make([]string, 0, len(fg.srcs))
270 outs := make([]string, 0, len(fg.srcs))
271 for _, p := range fg.srcs {
272 ins = append(ins, p.String())
273 outs = append(outs, p.Rel())
274 }
275 return []blueprint.JSONAction{
276 blueprint.JSONAction{
277 Inputs: ins,
278 Outputs: outs,
279 },
280 }
281}
282
Liz Kammer5bde22f2021-04-19 14:04:14 -0400283func (fg *fileGroup) GenerateAndroidBuildActions(ctx ModuleContext) {
Liz Kammer5bde22f2021-04-19 14:04:14 -0400284 fg.srcs = PathsForModuleSrcExcludes(ctx, fg.properties.Srcs, fg.properties.Exclude_srcs)
Colin Cross2fafa3e2019-03-05 12:39:51 -0800285 if fg.properties.Path != nil {
286 fg.srcs = PathsWithModuleSrcSubDir(ctx, fg.srcs, String(fg.properties.Path))
287 }
Colin Cross068e0fe2016-12-13 15:23:47 -0800288}
289
Pirama Arumuga Nainar955dc492018-04-17 14:58:42 -0700290func (fg *fileGroup) Srcs() Paths {
291 return append(Paths{}, fg.srcs...)
Colin Cross068e0fe2016-12-13 15:23:47 -0800292}
Colin Crossd91d7ac2017-09-12 22:52:12 -0700293
Dan Willemsen6a6478d2020-07-17 19:28:53 -0700294func (fg *fileGroup) MakeVars(ctx MakeVarsModuleContext) {
295 if makeVar := String(fg.properties.Export_to_make_var); makeVar != "" {
296 ctx.StrictRaw(makeVar, strings.Join(fg.srcs.Strings(), " "))
Colin Crossd91d7ac2017-09-12 22:52:12 -0700297 }
298}
Chris Parsonsf874e462022-05-10 13:50:12 -0400299
300func (fg *fileGroup) QueueBazelCall(ctx BaseModuleContext) {
301 bazelCtx := ctx.Config().BazelContext
302
303 bazelCtx.QueueBazelRequest(
304 fg.GetBazelLabel(ctx, fg),
305 cquery.GetOutputFiles,
Yu Liue4312402023-01-18 09:15:31 -0800306 configKey{arch: Common.String(), osType: CommonOS})
Chris Parsonsf874e462022-05-10 13:50:12 -0400307}
308
309func (fg *fileGroup) IsMixedBuildSupported(ctx BaseModuleContext) bool {
Liz Kammer748209c2022-10-24 10:43:27 -0400310 // TODO(b/247782695), TODO(b/242847534) Fix mixed builds for filegroups
311 return false
Chris Parsonsf874e462022-05-10 13:50:12 -0400312}
313
314func (fg *fileGroup) ProcessBazelQueryResponse(ctx ModuleContext) {
Vinh Tran16fe8e12022-08-16 16:45:44 -0400315 bazelCtx := ctx.Config().BazelContext
316 // This is a short-term solution because we rely on info from Android.bp to handle
317 // a converted module. This will block when we want to remove Android.bp for all
318 // converted modules at some point.
319 // TODO(b/242847534): Implement a long-term solution in which we don't need to rely
320 // on info form Android.bp for modules that are already converted to Bazel
321 relativeRoot := ctx.ModuleDir()
Chris Parsonsf874e462022-05-10 13:50:12 -0400322 if fg.properties.Path != nil {
Vinh Tran16fe8e12022-08-16 16:45:44 -0400323 relativeRoot = filepath.Join(relativeRoot, *fg.properties.Path)
Chris Parsonsf874e462022-05-10 13:50:12 -0400324 }
325
Yu Liue4312402023-01-18 09:15:31 -0800326 filePaths, err := bazelCtx.GetOutputFiles(fg.GetBazelLabel(ctx, fg), configKey{arch: Common.String(), osType: CommonOS})
Chris Parsonsf874e462022-05-10 13:50:12 -0400327 if err != nil {
328 ctx.ModuleErrorf(err.Error())
329 return
330 }
331
332 bazelOuts := make(Paths, 0, len(filePaths))
333 for _, p := range filePaths {
Vinh Tran16fe8e12022-08-16 16:45:44 -0400334 bazelOuts = append(bazelOuts, PathForBazelOutRelative(ctx, relativeRoot, p))
Chris Parsonsf874e462022-05-10 13:50:12 -0400335 }
Chris Parsonsf874e462022-05-10 13:50:12 -0400336 fg.srcs = bazelOuts
337}
Vinh Tran444154d2022-08-16 13:10:31 -0400338
339func (fg *fileGroup) ShouldConvertToAidlLibrary(ctx BazelConversionPathContext) bool {
Yu Liu2aa806b2022-09-01 11:54:47 -0700340 return fg.shouldConvertToLibrary(ctx, ".aidl")
341}
342
343func (fg *fileGroup) ShouldConvertToProtoLibrary(ctx BazelConversionPathContext) bool {
344 return fg.shouldConvertToLibrary(ctx, ".proto")
345}
346
347func (fg *fileGroup) shouldConvertToLibrary(ctx BazelConversionPathContext, suffix string) bool {
Vinh Tran444154d2022-08-16 13:10:31 -0400348 if len(fg.properties.Srcs) == 0 || !fg.ShouldConvertWithBp2build(ctx) {
349 return false
350 }
351 for _, src := range fg.properties.Srcs {
Yu Liu2aa806b2022-09-01 11:54:47 -0700352 if !strings.HasSuffix(src, suffix) {
Vinh Tran444154d2022-08-16 13:10:31 -0400353 return false
354 }
355 }
356 return true
357}
358
359func (fg *fileGroup) GetAidlLibraryLabel(ctx BazelConversionPathContext) string {
Yu Liu2aa806b2022-09-01 11:54:47 -0700360 return fg.getFileGroupAsLibraryLabel(ctx)
361}
362
363func (fg *fileGroup) GetProtoLibraryLabel(ctx BazelConversionPathContext) string {
364 return fg.getFileGroupAsLibraryLabel(ctx) + convertedProtoLibrarySuffix
365}
366
367func (fg *fileGroup) getFileGroupAsLibraryLabel(ctx BazelConversionPathContext) string {
Vinh Tran444154d2022-08-16 13:10:31 -0400368 if ctx.OtherModuleDir(fg.module) == ctx.ModuleDir() {
369 return ":" + fg.Name()
370 } else {
371 return fg.GetBazelLabel(ctx, fg)
372 }
373}
Sam Delmerico97bd1272022-08-25 14:45:31 -0400374
375// Given a name in srcs prop, check to see if the name references a filegroup
376// and the filegroup is converted to aidl_library
377func IsConvertedToAidlLibrary(ctx BazelConversionPathContext, name string) bool {
Yu Liu2aa806b2022-09-01 11:54:47 -0700378 if fg, ok := ToFileGroupAsLibrary(ctx, name); ok {
379 return fg.ShouldConvertToAidlLibrary(ctx)
380 }
381 return false
382}
383
384func ToFileGroupAsLibrary(ctx BazelConversionPathContext, name string) (FileGroupAsLibrary, bool) {
Sam Delmerico97bd1272022-08-25 14:45:31 -0400385 if module, ok := ctx.ModuleFromName(name); ok {
386 if IsFilegroup(ctx, module) {
Yu Liu2aa806b2022-09-01 11:54:47 -0700387 if fg, ok := module.(FileGroupAsLibrary); ok {
388 return fg, true
Sam Delmerico97bd1272022-08-25 14:45:31 -0400389 }
390 }
391 }
Yu Liu2aa806b2022-09-01 11:54:47 -0700392 return nil, false
Sam Delmerico97bd1272022-08-25 14:45:31 -0400393}
Anton Hansson7d6dd8b2023-03-06 11:26:17 +0000394
395// Defaults
396type FileGroupDefaults struct {
397 ModuleBase
398 DefaultsModuleBase
399}
400
401func FileGroupDefaultsFactory() Module {
402 module := &FileGroupDefaults{}
403 module.AddProperties(&fileGroupProperties{})
404 InitDefaultsModule(module)
405
406 return module
407}