blob: 42d955e4287cc2f9e9203edd8a207170a816fae5 [file] [log] [blame]
Alex Márquez Pérez Muñíz Díaz Púras Thaureauxf5a3eac2021-08-23 17:05:17 +00001// Copyright 2021 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
Liz Kammer2dd9ca42020-11-25 16:06:39 -080015package bp2build
16
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux0da7ce62021-08-23 17:04:20 +000017/*
18For shareable/common bp2build testing functionality and dumping ground for
19specific-but-shared functionality among tests in package
20*/
21
Liz Kammer2dd9ca42020-11-25 16:06:39 -080022import (
Liz Kammer7a210ac2021-09-22 15:52:58 -040023 "fmt"
Zi Wangfba0a212023-03-07 16:48:19 -080024 "sort"
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000025 "strings"
Rupert Shuttleworth06559d02021-05-19 09:14:26 -040026 "testing"
27
Spandan Das5af0bd32022-09-28 20:43:08 +000028 "github.com/google/blueprint/proptools"
29
Liz Kammer2dd9ca42020-11-25 16:06:39 -080030 "android/soong/android"
Sam Delmerico24c56032022-03-28 19:53:03 +000031 "android/soong/android/allowlists"
Jingwen Chen73850672020-12-14 08:25:34 -050032 "android/soong/bazel"
Liz Kammer2dd9ca42020-11-25 16:06:39 -080033)
34
Jingwen Chen91220d72021-03-24 02:18:33 -040035var (
Rupert Shuttleworth06559d02021-05-19 09:14:26 -040036 buildDir string
Jingwen Chen91220d72021-03-24 02:18:33 -040037)
38
Jingwen Chen5146ac02021-09-02 11:44:42 +000039func checkError(t *testing.T, errs []error, expectedErr error) bool {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000040 t.Helper()
Jingwen Chen5146ac02021-09-02 11:44:42 +000041
Jingwen Chen5146ac02021-09-02 11:44:42 +000042 if len(errs) != 1 {
Liz Kammer6eff3232021-08-26 08:37:59 -040043 return false
Jingwen Chen5146ac02021-09-02 11:44:42 +000044 }
Liz Kammer54309532021-12-14 12:21:22 -050045 if strings.Contains(errs[0].Error(), expectedErr.Error()) {
Jingwen Chen5146ac02021-09-02 11:44:42 +000046 return true
47 }
48
49 return false
50}
51
Sam Delmerico3177a6e2022-06-21 19:28:33 +000052func errored(t *testing.T, tc Bp2buildTestCase, errs []error) bool {
Jingwen Chen5146ac02021-09-02 11:44:42 +000053 t.Helper()
Sam Delmerico3177a6e2022-06-21 19:28:33 +000054 if tc.ExpectedErr != nil {
Jingwen Chen5146ac02021-09-02 11:44:42 +000055 // Rely on checkErrors, as this test case is expected to have an error.
56 return false
57 }
58
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000059 if len(errs) > 0 {
60 for _, err := range errs {
Sam Delmerico3177a6e2022-06-21 19:28:33 +000061 t.Errorf("%s: %s", tc.Description, err)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000062 }
63 return true
64 }
Jingwen Chen5146ac02021-09-02 11:44:42 +000065
66 // All good, continue execution.
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000067 return false
68}
69
Trevor Radcliffe1b4b2d92022-09-01 18:57:01 +000070func RunBp2BuildTestCaseSimple(t *testing.T, tc Bp2buildTestCase) {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000071 t.Helper()
Sam Delmerico3177a6e2022-06-21 19:28:33 +000072 RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000073}
74
Sam Delmerico3177a6e2022-06-21 19:28:33 +000075type Bp2buildTestCase struct {
76 Description string
77 ModuleTypeUnderTest string
78 ModuleTypeUnderTestFactory android.ModuleFactory
Sam Delmerico5840afc2023-06-12 15:44:03 -040079 // Text to add to the toplevel, root Android.bp file. If Dir is not set, all
80 // ExpectedBazelTargets are assumed to be generated by this file.
Chris Parsons39a16972023-06-08 14:28:51 +000081 Blueprint string
Sam Delmerico5840afc2023-06-12 15:44:03 -040082 // ExpectedBazelTargets compares the BazelTargets generated in `Dir` (if not empty).
83 // Otherwise, it checks the BazelTargets generated by `Blueprint` in the root directory.
84 ExpectedBazelTargets []string
Cole Faust3d927232023-06-27 22:52:07 +000085 Filesystem map[string]string
Sam Delmerico5840afc2023-06-12 15:44:03 -040086 // Dir sets the directory which will be compared against the targets in ExpectedBazelTargets.
87 // This should used in conjunction with the Filesystem property to check for targets
88 // generated from a directory that is not the root.
89 // If not set, all ExpectedBazelTargets are assumed to be generated by the text in the
90 // Blueprint property.
91 Dir string
Trevor Radcliffe58ea4512022-04-07 20:36:39 +000092 // An error with a string contained within the string of the expected error
Sam Delmerico3177a6e2022-06-21 19:28:33 +000093 ExpectedErr error
94 UnconvertedDepsMode unconvertedDepsMode
Jingwen Chen0eeaeb82022-09-21 10:27:42 +000095
96 // For every directory listed here, the BUILD file for that directory will
97 // be merged with the generated BUILD file. This allows custom BUILD targets
98 // to be used in tests, or use BUILD files to draw package boundaries.
99 KeepBuildFileForDirs []string
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000100}
101
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000102func RunBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
Liz Kammerffc17e42022-11-23 09:42:05 -0500103 t.Helper()
Paul Duffin4c0765a2022-10-29 17:48:00 +0100104 bp2buildSetup := android.GroupFixturePreparers(
105 android.FixtureRegisterWithContext(registerModuleTypes),
106 SetBp2BuildTestRunner,
107 )
Spandan Das5af0bd32022-09-28 20:43:08 +0000108 runBp2BuildTestCaseWithSetup(t, bp2buildSetup, tc)
109}
110
111func RunApiBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
Liz Kammerffc17e42022-11-23 09:42:05 -0500112 t.Helper()
Paul Duffin4c0765a2022-10-29 17:48:00 +0100113 apiBp2BuildSetup := android.GroupFixturePreparers(
114 android.FixtureRegisterWithContext(registerModuleTypes),
115 SetApiBp2BuildTestRunner,
116 )
Spandan Das5af0bd32022-09-28 20:43:08 +0000117 runBp2BuildTestCaseWithSetup(t, apiBp2BuildSetup, tc)
118}
119
Paul Duffin4c0765a2022-10-29 17:48:00 +0100120func runBp2BuildTestCaseWithSetup(t *testing.T, extraPreparer android.FixturePreparer, tc Bp2buildTestCase) {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000121 t.Helper()
Cole Faust3d927232023-06-27 22:52:07 +0000122 dir := "."
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000123 filesystem := make(map[string][]byte)
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000124 for f, content := range tc.Filesystem {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000125 filesystem[f] = []byte(content)
126 }
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000127
Paul Duffin4c0765a2022-10-29 17:48:00 +0100128 preparers := []android.FixturePreparer{
129 extraPreparer,
130 android.FixtureMergeMockFs(filesystem),
131 android.FixtureWithRootAndroidBp(tc.Blueprint),
132 android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
133 ctx.RegisterModuleType(tc.ModuleTypeUnderTest, tc.ModuleTypeUnderTestFactory)
134 }),
Cole Faust3d927232023-06-27 22:52:07 +0000135 android.FixtureModifyContext(func(ctx *android.TestContext) {
Paul Duffin4c0765a2022-10-29 17:48:00 +0100136 // A default configuration for tests to not have to specify bp2build_available on top level
137 // targets.
138 bp2buildConfig := android.NewBp2BuildAllowlist().SetDefaultConfig(
139 allowlists.Bp2BuildConfig{
140 android.Bp2BuildTopLevel: allowlists.Bp2BuildDefaultTrueRecursively,
141 },
142 )
Cole Faust3d927232023-06-27 22:52:07 +0000143 for _, f := range tc.KeepBuildFileForDirs {
Paul Duffin4c0765a2022-10-29 17:48:00 +0100144 bp2buildConfig.SetKeepExistingBuildFile(map[string]bool{
145 f: /*recursive=*/ false,
146 })
147 }
148 ctx.RegisterBp2BuildConfig(bp2buildConfig)
Chris Parsons39a16972023-06-08 14:28:51 +0000149 // This setting is added to bp2build invocations. It prevents bp2build
150 // from cloning modules to their original state after mutators run. This
151 // would lose some data intentionally set by these mutators.
152 ctx.SkipCloneModulesAfterMutators = true
Paul Duffin4c0765a2022-10-29 17:48:00 +0100153 }),
154 android.FixtureModifyEnv(func(env map[string]string) {
155 if tc.UnconvertedDepsMode == errorModulesUnconvertedDeps {
156 env["BP2BUILD_ERROR_UNCONVERTED"] = "true"
157 }
158 }),
Jingwen Chen5146ac02021-09-02 11:44:42 +0000159 }
160
Paul Duffin4c0765a2022-10-29 17:48:00 +0100161 preparer := android.GroupFixturePreparers(preparers...)
162 if tc.ExpectedErr != nil {
163 pattern := "\\Q" + tc.ExpectedErr.Error() + "\\E"
164 preparer = preparer.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(pattern))
165 }
166 result := preparer.RunTestWithCustomResult(t).(*BazelTestResult)
167 if len(result.Errs) > 0 {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000168 return
169 }
170
Cole Faust3d927232023-06-27 22:52:07 +0000171 checkDir := dir
172 if tc.Dir != "" {
173 checkDir = tc.Dir
174 }
Paul Duffin4c0765a2022-10-29 17:48:00 +0100175 expectedTargets := map[string][]string{
176 checkDir: tc.ExpectedBazelTargets,
Liz Kammer6eff3232021-08-26 08:37:59 -0400177 }
Paul Duffin4c0765a2022-10-29 17:48:00 +0100178
179 result.CompareAllBazelTargets(t, tc.Description, expectedTargets, true)
180}
181
182// SetBp2BuildTestRunner customizes the test fixture mechanism to run tests in Bp2Build mode.
183var SetBp2BuildTestRunner = android.FixtureSetTestRunner(&bazelTestRunner{Bp2Build})
184
185// SetApiBp2BuildTestRunner customizes the test fixture mechanism to run tests in ApiBp2build mode.
186var SetApiBp2BuildTestRunner = android.FixtureSetTestRunner(&bazelTestRunner{ApiBp2build})
187
188// bazelTestRunner customizes the test fixture mechanism to run tests of the bp2build and
189// apiBp2build build modes.
190type bazelTestRunner struct {
191 mode CodegenMode
192}
193
194func (b *bazelTestRunner) FinalPreparer(result *android.TestResult) android.CustomTestResult {
195 ctx := result.TestContext
196 switch b.mode {
197 case Bp2Build:
198 ctx.RegisterForBazelConversion()
199 case ApiBp2build:
200 ctx.RegisterForApiBazelConversion()
201 default:
202 panic(fmt.Errorf("unknown build mode: %d", b.mode))
203 }
204
205 return &BazelTestResult{TestResult: result}
206}
207
208func (b *bazelTestRunner) PostParseProcessor(result android.CustomTestResult) {
209 bazelResult := result.(*BazelTestResult)
210 ctx := bazelResult.TestContext
211 config := bazelResult.Config
212 _, errs := ctx.ResolveDependencies(config)
213 if bazelResult.CollateErrs(errs) {
214 return
215 }
216
Chris Parsons39a16972023-06-08 14:28:51 +0000217 codegenMode := Bp2Build
218 if ctx.Config().BuildMode == android.ApiBp2build {
219 codegenMode = ApiBp2build
220 }
221 codegenCtx := NewCodegenContext(config, ctx.Context, codegenMode, "")
Paul Duffin4c0765a2022-10-29 17:48:00 +0100222 res, errs := GenerateBazelTargets(codegenCtx, false)
223 if bazelResult.CollateErrs(errs) {
224 return
225 }
226
227 // Store additional data for access by tests.
228 bazelResult.conversionResults = res
229}
230
231// BazelTestResult is a wrapper around android.TestResult to provide type safe access to the bazel
232// specific data stored by the bazelTestRunner.
233type BazelTestResult struct {
234 *android.TestResult
235
236 // The result returned by the GenerateBazelTargets function.
237 conversionResults
238}
239
240// CompareAllBazelTargets compares the BazelTargets produced by the test for all the directories
241// with the supplied set of expected targets.
242//
243// If ignoreUnexpected=false then this enforces an exact match where every BazelTarget produced must
244// have a corresponding expected BazelTarget.
245//
246// If ignoreUnexpected=true then it will ignore directories for which there are no expected targets.
247func (b BazelTestResult) CompareAllBazelTargets(t *testing.T, description string, expectedTargets map[string][]string, ignoreUnexpected bool) {
Liz Kammer2b3f56e2023-03-23 11:51:49 -0400248 t.Helper()
Paul Duffin4c0765a2022-10-29 17:48:00 +0100249 actualTargets := b.buildFileToTargets
250
251 // Generate the sorted set of directories to check.
Cole Faust18994c72023-02-28 16:02:16 -0800252 dirsToCheck := android.SortedKeys(expectedTargets)
Paul Duffin4c0765a2022-10-29 17:48:00 +0100253 if !ignoreUnexpected {
254 // This needs to perform an exact match so add the directories in which targets were
255 // produced to the list of directories to check.
Cole Faust18994c72023-02-28 16:02:16 -0800256 dirsToCheck = append(dirsToCheck, android.SortedKeys(actualTargets)...)
Paul Duffin4c0765a2022-10-29 17:48:00 +0100257 dirsToCheck = android.SortedUniqueStrings(dirsToCheck)
258 }
259
260 for _, dir := range dirsToCheck {
261 expected := expectedTargets[dir]
262 actual := actualTargets[dir]
263
264 if expected == nil {
265 if actual != nil {
266 t.Errorf("did not expect any bazel modules in %q but found %d", dir, len(actual))
267 }
268 } else if actual == nil {
269 expectedCount := len(expected)
270 if expectedCount > 0 {
271 t.Errorf("expected %d bazel modules in %q but did not find any", expectedCount, dir)
272 }
273 } else {
274 b.CompareBazelTargets(t, description, expected, actual)
275 }
276 }
277}
278
279func (b BazelTestResult) CompareBazelTargets(t *testing.T, description string, expectedContents []string, actualTargets BazelTargets) {
Liz Kammer748d7072023-01-25 12:07:43 -0500280 t.Helper()
Paul Duffin4c0765a2022-10-29 17:48:00 +0100281 if actualCount, expectedCount := len(actualTargets), len(expectedContents); actualCount != expectedCount {
Sasha Smundak9d2f1742022-08-04 13:28:38 -0700282 t.Errorf("%s: Expected %d bazel target (%s), got %d (%s)",
Paul Duffin4c0765a2022-10-29 17:48:00 +0100283 description, expectedCount, expectedContents, actualCount, actualTargets)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000284 } else {
Zi Wangfba0a212023-03-07 16:48:19 -0800285 sort.SliceStable(actualTargets, func(i, j int) bool {
286 return actualTargets[i].name < actualTargets[j].name
287 })
288 sort.SliceStable(expectedContents, func(i, j int) bool {
289 return getTargetName(expectedContents[i]) < getTargetName(expectedContents[j])
290 })
Paul Duffin4c0765a2022-10-29 17:48:00 +0100291 for i, actualTarget := range actualTargets {
292 if w, g := expectedContents[i], actualTarget.content; w != g {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000293 t.Errorf(
Paul Duffin4c0765a2022-10-29 17:48:00 +0100294 "%s[%d]: Expected generated Bazel target to be `%s`, got `%s`",
295 description, i, w, g)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000296 }
297 }
298 }
299}
300
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800301type nestedProps struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500302 Nested_prop *string
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800303}
304
Liz Kammer32a03392021-09-14 11:17:21 -0400305type EmbeddedProps struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500306 Embedded_prop *string
Liz Kammer32a03392021-09-14 11:17:21 -0400307}
308
309type OtherEmbeddedProps struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500310 Other_embedded_prop *string
Liz Kammer32a03392021-09-14 11:17:21 -0400311}
312
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800313type customProps struct {
Liz Kammer32a03392021-09-14 11:17:21 -0400314 EmbeddedProps
315 *OtherEmbeddedProps
316
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800317 Bool_prop bool
318 Bool_ptr_prop *bool
319 // Ensure that properties tagged `blueprint:mutated` are omitted
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000320 Int_prop int `blueprint:"mutated"`
321 Int64_ptr_prop *int64
322 String_prop string
323 String_literal_prop *string `android:"arch_variant"`
324 String_ptr_prop *string
325 String_list_prop []string
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800326
327 Nested_props nestedProps
328 Nested_props_ptr *nestedProps
Liz Kammer4562a3b2021-04-21 18:15:34 -0400329
Liz Kammer32b77cf2021-08-04 15:17:02 -0400330 Arch_paths []string `android:"path,arch_variant"`
331 Arch_paths_exclude []string `android:"path,arch_variant"`
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400332
333 // Prop used to indicate this conversion should be 1 module -> multiple targets
334 One_to_many_prop *bool
Spandan Das5af0bd32022-09-28 20:43:08 +0000335
336 Api *string // File describing the APIs of this module
Spandan Das6a448ec2023-04-19 17:36:12 +0000337
338 Test_config_setting *bool // Used to test generation of config_setting targets
Spandan Das3131d672023-08-03 22:33:47 +0000339
340 Dir *string // Dir in which the Bazel Target will be created
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800341}
342
343type customModule struct {
344 android.ModuleBase
Liz Kammerea6666f2021-02-17 10:17:28 -0500345 android.BazelModuleBase
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800346
347 props customProps
348}
349
350// OutputFiles is needed because some instances of this module use dist with a
351// tag property which requires the module implements OutputFileProducer.
352func (m *customModule) OutputFiles(tag string) (android.Paths, error) {
353 return android.PathsForTesting("path" + tag), nil
354}
355
356func (m *customModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
357 // nothing for now.
358}
359
360func customModuleFactoryBase() android.Module {
361 module := &customModule{}
362 module.AddProperties(&module.props)
Liz Kammerea6666f2021-02-17 10:17:28 -0500363 android.InitBazelModule(module)
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800364 return module
365}
366
Liz Kammerdfeb1202022-05-13 17:20:20 -0400367func customModuleFactoryHostAndDevice() android.Module {
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800368 m := customModuleFactoryBase()
Liz Kammer4562a3b2021-04-21 18:15:34 -0400369 android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibBoth)
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800370 return m
371}
372
Liz Kammerdfeb1202022-05-13 17:20:20 -0400373func customModuleFactoryDeviceSupported() android.Module {
374 m := customModuleFactoryBase()
375 android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibBoth)
376 return m
377}
378
379func customModuleFactoryHostSupported() android.Module {
380 m := customModuleFactoryBase()
381 android.InitAndroidArchModule(m, android.HostSupported, android.MultilibBoth)
382 return m
383}
384
385func customModuleFactoryHostAndDeviceDefault() android.Module {
386 m := customModuleFactoryBase()
387 android.InitAndroidArchModule(m, android.HostAndDeviceDefault, android.MultilibBoth)
388 return m
389}
390
391func customModuleFactoryNeitherHostNorDeviceSupported() android.Module {
392 m := customModuleFactoryBase()
393 android.InitAndroidArchModule(m, android.NeitherHostNorDeviceSupported, android.MultilibBoth)
394 return m
395}
396
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800397type testProps struct {
398 Test_prop struct {
399 Test_string_prop string
400 }
401}
402
403type customTestModule struct {
404 android.ModuleBase
405
406 props customProps
407 test_props testProps
408}
409
410func (m *customTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
411 // nothing for now.
412}
413
414func customTestModuleFactoryBase() android.Module {
415 m := &customTestModule{}
416 m.AddProperties(&m.props)
417 m.AddProperties(&m.test_props)
418 return m
419}
420
421func customTestModuleFactory() android.Module {
422 m := customTestModuleFactoryBase()
423 android.InitAndroidModule(m)
424 return m
425}
426
427type customDefaultsModule struct {
428 android.ModuleBase
429 android.DefaultsModuleBase
430}
431
432func customDefaultsModuleFactoryBase() android.DefaultsModule {
433 module := &customDefaultsModule{}
434 module.AddProperties(&customProps{})
435 return module
436}
437
438func customDefaultsModuleFactoryBasic() android.Module {
439 return customDefaultsModuleFactoryBase()
440}
441
442func customDefaultsModuleFactory() android.Module {
443 m := customDefaultsModuleFactoryBase()
444 android.InitDefaultsModule(m)
445 return m
446}
Jingwen Chen73850672020-12-14 08:25:34 -0500447
Liz Kammer32a03392021-09-14 11:17:21 -0400448type EmbeddedAttr struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500449 Embedded_attr *string
Liz Kammer32a03392021-09-14 11:17:21 -0400450}
451
452type OtherEmbeddedAttr struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500453 Other_embedded_attr *string
Liz Kammer32a03392021-09-14 11:17:21 -0400454}
455
Jingwen Chen73850672020-12-14 08:25:34 -0500456type customBazelModuleAttributes struct {
Liz Kammer32a03392021-09-14 11:17:21 -0400457 EmbeddedAttr
458 *OtherEmbeddedAttr
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000459 String_literal_prop bazel.StringAttribute
460 String_ptr_prop *string
461 String_list_prop []string
462 Arch_paths bazel.LabelListAttribute
Spandan Das5af0bd32022-09-28 20:43:08 +0000463 Api bazel.LabelAttribute
Jingwen Chen73850672020-12-14 08:25:34 -0500464}
465
Spandan Das3131d672023-08-03 22:33:47 +0000466func (m *customModule) dir() *string {
467 return m.props.Dir
468}
469
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400470func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400471 if p := m.props.One_to_many_prop; p != nil && *p {
472 customBp2buildOneToMany(ctx, m)
473 return
474 }
Liz Kammer4562a3b2021-04-21 18:15:34 -0400475
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000476 paths := bazel.LabelListAttribute{}
477 strAttr := bazel.StringAttribute{}
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400478 for axis, configToProps := range m.GetArchVariantProperties(ctx, &customProps{}) {
479 for config, props := range configToProps {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000480 if custProps, ok := props.(*customProps); ok {
481 if custProps.Arch_paths != nil {
482 paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrcExcludes(ctx, custProps.Arch_paths, custProps.Arch_paths_exclude))
483 }
484 if custProps.String_literal_prop != nil {
485 strAttr.SetSelectValue(axis, config, custProps.String_literal_prop)
486 }
Liz Kammer4562a3b2021-04-21 18:15:34 -0400487 }
488 }
Jingwen Chen73850672020-12-14 08:25:34 -0500489 }
Cole Faust912bc882023-03-08 12:29:50 -0800490 productVariableProps := android.ProductVariableProperties(ctx, ctx.Module())
Liz Kammer9d2d4102022-12-21 14:51:37 -0500491 if props, ok := productVariableProps["String_literal_prop"]; ok {
492 for c, p := range props {
493 if val, ok := p.(*string); ok {
494 strAttr.SetSelectValue(c.ConfigurationAxis(), c.SelectKey(), val)
495 }
496 }
497 }
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400498
499 paths.ResolveExcludes()
500
501 attrs := &customBazelModuleAttributes{
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000502 String_literal_prop: strAttr,
503 String_ptr_prop: m.props.String_ptr_prop,
504 String_list_prop: m.props.String_list_prop,
505 Arch_paths: paths,
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400506 }
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000507
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400508 attrs.Embedded_attr = m.props.Embedded_prop
509 if m.props.OtherEmbeddedProps != nil {
510 attrs.OtherEmbeddedAttr = &OtherEmbeddedAttr{Other_embedded_attr: m.props.OtherEmbeddedProps.Other_embedded_prop}
511 }
512
513 props := bazel.BazelTargetModuleProperties{
514 Rule_class: "custom",
515 }
516
Spandan Das3131d672023-08-03 22:33:47 +0000517 ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name(), Dir: m.dir()}, attrs)
Spandan Das6a448ec2023-04-19 17:36:12 +0000518
519 if proptools.Bool(m.props.Test_config_setting) {
520 m.createConfigSetting(ctx)
521 }
522
523}
524
525func (m *customModule) createConfigSetting(ctx android.TopDownMutatorContext) {
526 csa := bazel.ConfigSettingAttributes{
527 Flag_values: bazel.StringMapAttribute{
528 "//build/bazel/rules/my_string_setting": m.Name(),
529 },
530 }
531 ca := android.CommonAttributes{
532 Name: m.Name() + "_config_setting",
533 }
534 ctx.CreateBazelConfigSetting(
535 csa,
536 ca,
537 ctx.ModuleDir(),
538 )
Jingwen Chen73850672020-12-14 08:25:34 -0500539}
Jingwen Chen40067de2021-01-26 21:58:43 -0500540
Spandan Das5af0bd32022-09-28 20:43:08 +0000541var _ android.ApiProvider = (*customModule)(nil)
542
543func (c *customModule) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
544 props := bazel.BazelTargetModuleProperties{
545 Rule_class: "custom_api_contribution",
546 }
547 apiAttribute := bazel.MakeLabelAttribute(
548 android.BazelLabelForModuleSrcSingle(ctx, proptools.String(c.props.Api)).Label,
549 )
550 attrs := &customBazelModuleAttributes{
551 Api: *apiAttribute,
552 }
553 ctx.CreateBazelTargetModule(props,
554 android.CommonAttributes{Name: c.Name()},
555 attrs)
556}
557
Jingwen Chen40067de2021-01-26 21:58:43 -0500558// A bp2build mutator that uses load statements and creates a 1:M mapping from
559// module to target.
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400560func customBp2buildOneToMany(ctx android.TopDownMutatorContext, m *customModule) {
Jingwen Chen77e8b7b2021-02-05 03:03:24 -0500561
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400562 baseName := m.Name()
563 attrs := &customBazelModuleAttributes{}
Jingwen Chen1fd14692021-02-05 03:01:50 -0500564
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400565 myLibraryProps := bazel.BazelTargetModuleProperties{
566 Rule_class: "my_library",
567 Bzl_load_location: "//build/bazel/rules:rules.bzl",
Jingwen Chen40067de2021-01-26 21:58:43 -0500568 }
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400569 ctx.CreateBazelTargetModule(myLibraryProps, android.CommonAttributes{Name: baseName}, attrs)
570
571 protoLibraryProps := bazel.BazelTargetModuleProperties{
572 Rule_class: "proto_library",
573 Bzl_load_location: "//build/bazel/rules:proto.bzl",
574 }
575 ctx.CreateBazelTargetModule(protoLibraryProps, android.CommonAttributes{Name: baseName + "_proto_library_deps"}, attrs)
576
577 myProtoLibraryProps := bazel.BazelTargetModuleProperties{
578 Rule_class: "my_proto_library",
579 Bzl_load_location: "//build/bazel/rules:proto.bzl",
580 }
581 ctx.CreateBazelTargetModule(myProtoLibraryProps, android.CommonAttributes{Name: baseName + "_my_proto_library_deps"}, attrs)
Jingwen Chen40067de2021-01-26 21:58:43 -0500582}
Jingwen Chenba369ad2021-02-22 10:19:34 -0500583
584// Helper method for tests to easily access the targets in a dir.
Liz Kammer6eff3232021-08-26 08:37:59 -0400585func generateBazelTargetsForDir(codegenCtx *CodegenContext, dir string) (BazelTargets, []error) {
Rupert Shuttleworth2a4fc3e2021-04-21 07:10:09 -0400586 // TODO: Set generateFilegroups to true and/or remove the generateFilegroups argument completely
Liz Kammer6eff3232021-08-26 08:37:59 -0400587 res, err := GenerateBazelTargets(codegenCtx, false)
Alix94e26032022-08-16 20:37:33 +0000588 if err != nil {
589 return BazelTargets{}, err
590 }
Liz Kammer6eff3232021-08-26 08:37:59 -0400591 return res.buildFileToTargets[dir], err
Jingwen Chenba369ad2021-02-22 10:19:34 -0500592}
Liz Kammer32b77cf2021-08-04 15:17:02 -0400593
594func registerCustomModuleForBp2buildConversion(ctx *android.TestContext) {
Liz Kammerdfeb1202022-05-13 17:20:20 -0400595 ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
Liz Kammer32b77cf2021-08-04 15:17:02 -0400596 ctx.RegisterForBazelConversion()
597}
Liz Kammer7a210ac2021-09-22 15:52:58 -0400598
599func simpleModuleDoNotConvertBp2build(typ, name string) string {
600 return fmt.Sprintf(`
601%s {
602 name: "%s",
603 bazel_module: { bp2build_available: false },
604}`, typ, name)
605}
Liz Kammer78cfdaa2021-11-08 12:56:31 -0500606
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000607type AttrNameToString map[string]string
Liz Kammer78cfdaa2021-11-08 12:56:31 -0500608
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000609func (a AttrNameToString) clone() AttrNameToString {
610 newAttrs := make(AttrNameToString, len(a))
Liz Kammerdfeb1202022-05-13 17:20:20 -0400611 for k, v := range a {
612 newAttrs[k] = v
613 }
614 return newAttrs
615}
616
617// makeBazelTargetNoRestrictions returns bazel target build file definition that can be host or
618// device specific, or independent of host/device.
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000619func makeBazelTargetHostOrDevice(typ, name string, attrs AttrNameToString, hod android.HostOrDeviceSupported) string {
Liz Kammerdfeb1202022-05-13 17:20:20 -0400620 if _, ok := attrs["target_compatible_with"]; !ok {
621 switch hod {
622 case android.HostSupported:
623 attrs["target_compatible_with"] = `select({
624 "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
625 "//conditions:default": [],
626 })`
627 case android.DeviceSupported:
628 attrs["target_compatible_with"] = `["//build/bazel/platforms/os:android"]`
629 }
630 }
631
Liz Kammer78cfdaa2021-11-08 12:56:31 -0500632 attrStrings := make([]string, 0, len(attrs)+1)
Sasha Smundakfb589492022-08-04 11:13:27 -0700633 if name != "" {
634 attrStrings = append(attrStrings, fmt.Sprintf(` name = "%s",`, name))
635 }
Cole Faust18994c72023-02-28 16:02:16 -0800636 for _, k := range android.SortedKeys(attrs) {
Liz Kammer78cfdaa2021-11-08 12:56:31 -0500637 attrStrings = append(attrStrings, fmt.Sprintf(" %s = %s,", k, attrs[k]))
638 }
639 return fmt.Sprintf(`%s(
640%s
641)`, typ, strings.Join(attrStrings, "\n"))
642}
Liz Kammerdfeb1202022-05-13 17:20:20 -0400643
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000644// MakeBazelTargetNoRestrictions returns bazel target build file definition that does not add a
Liz Kammerdfeb1202022-05-13 17:20:20 -0400645// target_compatible_with. This is useful for module types like filegroup and genrule that arch not
646// arch variant
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000647func MakeBazelTargetNoRestrictions(typ, name string, attrs AttrNameToString) string {
Liz Kammerdfeb1202022-05-13 17:20:20 -0400648 return makeBazelTargetHostOrDevice(typ, name, attrs, android.HostAndDeviceDefault)
649}
650
651// makeBazelTargetNoRestrictions returns bazel target build file definition that is device specific
652// as this is the most common default in Soong.
Alixe06d75b2022-08-31 18:28:19 +0000653func MakeBazelTarget(typ, name string, attrs AttrNameToString) string {
Liz Kammerdfeb1202022-05-13 17:20:20 -0400654 return makeBazelTargetHostOrDevice(typ, name, attrs, android.DeviceSupported)
655}
Sasha Smundak9d2f1742022-08-04 13:28:38 -0700656
657type ExpectedRuleTarget struct {
658 Rule string
659 Name string
660 Attrs AttrNameToString
661 Hod android.HostOrDeviceSupported
662}
663
664func (ebr ExpectedRuleTarget) String() string {
665 return makeBazelTargetHostOrDevice(ebr.Rule, ebr.Name, ebr.Attrs, ebr.Hod)
666}
Trevor Radcliffe087af542022-09-16 15:36:10 +0000667
668func makeCcStubSuiteTargets(name string, attrs AttrNameToString) string {
669 if _, hasStubs := attrs["stubs_symbol_file"]; !hasStubs {
670 return ""
671 }
672 STUB_SUITE_ATTRS := map[string]string{
Sam Delmerico5f906492023-03-15 18:06:18 -0400673 "stubs_symbol_file": "symbol_file",
674 "stubs_versions": "versions",
675 "soname": "soname",
676 "source_library_label": "source_library_label",
Trevor Radcliffe087af542022-09-16 15:36:10 +0000677 }
678
679 stubSuiteAttrs := AttrNameToString{}
680 for key, _ := range attrs {
681 if _, stubSuiteAttr := STUB_SUITE_ATTRS[key]; stubSuiteAttr {
682 stubSuiteAttrs[STUB_SUITE_ATTRS[key]] = attrs[key]
Sam Delmerico5f906492023-03-15 18:06:18 -0400683 } else {
684 panic(fmt.Sprintf("unused cc_stub_suite attr %q\n", key))
Trevor Radcliffe087af542022-09-16 15:36:10 +0000685 }
686 }
687 return MakeBazelTarget("cc_stub_suite", name+"_stub_libs", stubSuiteAttrs)
688}
Alix341484b2022-10-31 19:08:18 +0000689
690func MakeNeverlinkDuplicateTarget(moduleType string, name string) string {
Liz Kammer02914402023-08-07 13:38:18 -0400691 return MakeNeverlinkDuplicateTargetWithAttrs(moduleType, name, AttrNameToString{
692 "sdk_version": `"current"`, // use as default
693 })
Romain Jobredeaux2eef2e12023-02-24 12:07:08 -0500694}
695
696func MakeNeverlinkDuplicateTargetWithAttrs(moduleType string, name string, extraAttrs AttrNameToString) string {
697 attrs := extraAttrs
698 attrs["neverlink"] = `True`
699 attrs["exports"] = `[":` + name + `"]`
700 return MakeBazelTarget(moduleType, name+"-neverlink", attrs)
Alix341484b2022-10-31 19:08:18 +0000701}
Zi Wangfba0a212023-03-07 16:48:19 -0800702
703func getTargetName(targetContent string) string {
704 data := strings.Split(targetContent, "name = \"")
705 if len(data) < 2 {
706 return ""
707 } else {
708 endIndex := strings.Index(data[1], "\"")
709 return data[1][:endIndex]
710 }
711}