blob: 7333c0b50519765f219443537b7ec0598cdfb325 [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"
Chris Parsons5011e612023-09-13 23:33:20 +000024 "path/filepath"
Zi Wangfba0a212023-03-07 16:48:19 -080025 "sort"
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000026 "strings"
Rupert Shuttleworth06559d02021-05-19 09:14:26 -040027 "testing"
28
Spandan Das5af0bd32022-09-28 20:43:08 +000029 "github.com/google/blueprint/proptools"
30
Liz Kammer2dd9ca42020-11-25 16:06:39 -080031 "android/soong/android"
Sam Delmerico24c56032022-03-28 19:53:03 +000032 "android/soong/android/allowlists"
Jingwen Chen73850672020-12-14 08:25:34 -050033 "android/soong/bazel"
Liz Kammer2dd9ca42020-11-25 16:06:39 -080034)
35
Jingwen Chen91220d72021-03-24 02:18:33 -040036var (
Rupert Shuttleworth06559d02021-05-19 09:14:26 -040037 buildDir string
Jingwen Chen91220d72021-03-24 02:18:33 -040038)
39
Jingwen Chen5146ac02021-09-02 11:44:42 +000040func 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 +000041 t.Helper()
Jingwen Chen5146ac02021-09-02 11:44:42 +000042
Jingwen Chen5146ac02021-09-02 11:44:42 +000043 if len(errs) != 1 {
Liz Kammer6eff3232021-08-26 08:37:59 -040044 return false
Jingwen Chen5146ac02021-09-02 11:44:42 +000045 }
Liz Kammer54309532021-12-14 12:21:22 -050046 if strings.Contains(errs[0].Error(), expectedErr.Error()) {
Jingwen Chen5146ac02021-09-02 11:44:42 +000047 return true
48 }
49
50 return false
51}
52
Sam Delmerico3177a6e2022-06-21 19:28:33 +000053func errored(t *testing.T, tc Bp2buildTestCase, errs []error) bool {
Jingwen Chen5146ac02021-09-02 11:44:42 +000054 t.Helper()
Sam Delmerico3177a6e2022-06-21 19:28:33 +000055 if tc.ExpectedErr != nil {
Jingwen Chen5146ac02021-09-02 11:44:42 +000056 // Rely on checkErrors, as this test case is expected to have an error.
57 return false
58 }
59
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000060 if len(errs) > 0 {
61 for _, err := range errs {
Sam Delmerico3177a6e2022-06-21 19:28:33 +000062 t.Errorf("%s: %s", tc.Description, err)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000063 }
64 return true
65 }
Jingwen Chen5146ac02021-09-02 11:44:42 +000066
67 // All good, continue execution.
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000068 return false
69}
70
Trevor Radcliffe1b4b2d92022-09-01 18:57:01 +000071func RunBp2BuildTestCaseSimple(t *testing.T, tc Bp2buildTestCase) {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000072 t.Helper()
Sam Delmerico3177a6e2022-06-21 19:28:33 +000073 RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000074}
75
Sam Delmerico3177a6e2022-06-21 19:28:33 +000076type Bp2buildTestCase struct {
77 Description string
78 ModuleTypeUnderTest string
79 ModuleTypeUnderTestFactory android.ModuleFactory
Sam Delmerico5840afc2023-06-12 15:44:03 -040080 // Text to add to the toplevel, root Android.bp file. If Dir is not set, all
81 // ExpectedBazelTargets are assumed to be generated by this file.
Chris Parsons39a16972023-06-08 14:28:51 +000082 Blueprint string
Sam Delmerico5840afc2023-06-12 15:44:03 -040083 // ExpectedBazelTargets compares the BazelTargets generated in `Dir` (if not empty).
84 // Otherwise, it checks the BazelTargets generated by `Blueprint` in the root directory.
85 ExpectedBazelTargets []string
Chris Parsons5011e612023-09-13 23:33:20 +000086 // AlreadyExistingBuildContents, if non-empty, simulates an already-present source BUILD file
87 // in the directory under test. The BUILD file has the given contents. This BUILD file
88 // will also be treated as "BUILD file to keep" by the simulated bp2build environment.
89 AlreadyExistingBuildContents string
90 // StubbedBuildDefinitions, if non-empty, adds stub definitions to an already-present source
91 // BUILD file in the directory under test, for each target name given. These stub definitions
92 // are added to the BUILD file given in AlreadyExistingBuildContents, if it is set.
93 StubbedBuildDefinitions []string
94
95 Filesystem map[string]string
Sam Delmerico5840afc2023-06-12 15:44:03 -040096 // Dir sets the directory which will be compared against the targets in ExpectedBazelTargets.
97 // This should used in conjunction with the Filesystem property to check for targets
98 // generated from a directory that is not the root.
99 // If not set, all ExpectedBazelTargets are assumed to be generated by the text in the
100 // Blueprint property.
101 Dir string
Trevor Radcliffe58ea4512022-04-07 20:36:39 +0000102 // An error with a string contained within the string of the expected error
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000103 ExpectedErr error
104 UnconvertedDepsMode unconvertedDepsMode
Jingwen Chen0eeaeb82022-09-21 10:27:42 +0000105
106 // For every directory listed here, the BUILD file for that directory will
107 // be merged with the generated BUILD file. This allows custom BUILD targets
108 // to be used in tests, or use BUILD files to draw package boundaries.
109 KeepBuildFileForDirs []string
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000110}
111
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000112func RunBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
Liz Kammerffc17e42022-11-23 09:42:05 -0500113 t.Helper()
Paul Duffin4c0765a2022-10-29 17:48:00 +0100114 bp2buildSetup := android.GroupFixturePreparers(
115 android.FixtureRegisterWithContext(registerModuleTypes),
116 SetBp2BuildTestRunner,
117 )
Spandan Das5af0bd32022-09-28 20:43:08 +0000118 runBp2BuildTestCaseWithSetup(t, bp2buildSetup, tc)
119}
120
Paul Duffin4c0765a2022-10-29 17:48:00 +0100121func 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 +0000122 t.Helper()
Chris Parsons5011e612023-09-13 23:33:20 +0000123 checkDir := "."
124 if tc.Dir != "" {
125 checkDir = tc.Dir
126 }
127 keepExistingBuildDirs := tc.KeepBuildFileForDirs
128 buildFilesToParse := []string{}
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000129 filesystem := make(map[string][]byte)
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000130 for f, content := range tc.Filesystem {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000131 filesystem[f] = []byte(content)
132 }
Chris Parsons5011e612023-09-13 23:33:20 +0000133 alreadyExistingBuildContents := tc.AlreadyExistingBuildContents
134 if len(tc.StubbedBuildDefinitions) > 0 {
135 for _, targetName := range tc.StubbedBuildDefinitions {
136 alreadyExistingBuildContents += MakeBazelTarget(
137 "bp2build_test_stub",
138 targetName,
139 AttrNameToString{})
140 }
141 }
142 if len(alreadyExistingBuildContents) > 0 {
143 buildFilePath := filepath.Join(checkDir, "BUILD")
144 filesystem[buildFilePath] = []byte(alreadyExistingBuildContents)
145 keepExistingBuildDirs = append(keepExistingBuildDirs, checkDir)
146 buildFilesToParse = append(buildFilesToParse, buildFilePath)
147 }
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000148
Paul Duffin4c0765a2022-10-29 17:48:00 +0100149 preparers := []android.FixturePreparer{
150 extraPreparer,
151 android.FixtureMergeMockFs(filesystem),
152 android.FixtureWithRootAndroidBp(tc.Blueprint),
153 android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
154 ctx.RegisterModuleType(tc.ModuleTypeUnderTest, tc.ModuleTypeUnderTestFactory)
155 }),
Chris Parsons5011e612023-09-13 23:33:20 +0000156 android.FixtureModifyContextWithMockFs(func(ctx *android.TestContext) {
Paul Duffin4c0765a2022-10-29 17:48:00 +0100157 // A default configuration for tests to not have to specify bp2build_available on top level
158 // targets.
159 bp2buildConfig := android.NewBp2BuildAllowlist().SetDefaultConfig(
160 allowlists.Bp2BuildConfig{
161 android.Bp2BuildTopLevel: allowlists.Bp2BuildDefaultTrueRecursively,
162 },
163 )
Chris Parsons5011e612023-09-13 23:33:20 +0000164 for _, f := range keepExistingBuildDirs {
Paul Duffin4c0765a2022-10-29 17:48:00 +0100165 bp2buildConfig.SetKeepExistingBuildFile(map[string]bool{
166 f: /*recursive=*/ false,
167 })
168 }
169 ctx.RegisterBp2BuildConfig(bp2buildConfig)
Chris Parsons39a16972023-06-08 14:28:51 +0000170 // This setting is added to bp2build invocations. It prevents bp2build
171 // from cloning modules to their original state after mutators run. This
172 // would lose some data intentionally set by these mutators.
173 ctx.SkipCloneModulesAfterMutators = true
Chris Parsons5011e612023-09-13 23:33:20 +0000174 err := ctx.RegisterExistingBazelTargets(".", buildFilesToParse)
175 if err != nil {
176 t.Errorf("error parsing build files in test setup: %s", err)
177 }
Paul Duffin4c0765a2022-10-29 17:48:00 +0100178 }),
179 android.FixtureModifyEnv(func(env map[string]string) {
180 if tc.UnconvertedDepsMode == errorModulesUnconvertedDeps {
181 env["BP2BUILD_ERROR_UNCONVERTED"] = "true"
182 }
183 }),
Jingwen Chen5146ac02021-09-02 11:44:42 +0000184 }
185
Paul Duffin4c0765a2022-10-29 17:48:00 +0100186 preparer := android.GroupFixturePreparers(preparers...)
187 if tc.ExpectedErr != nil {
188 pattern := "\\Q" + tc.ExpectedErr.Error() + "\\E"
189 preparer = preparer.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(pattern))
190 }
191 result := preparer.RunTestWithCustomResult(t).(*BazelTestResult)
192 if len(result.Errs) > 0 {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000193 return
194 }
195
Paul Duffin4c0765a2022-10-29 17:48:00 +0100196 expectedTargets := map[string][]string{
197 checkDir: tc.ExpectedBazelTargets,
Liz Kammer6eff3232021-08-26 08:37:59 -0400198 }
Paul Duffin4c0765a2022-10-29 17:48:00 +0100199
200 result.CompareAllBazelTargets(t, tc.Description, expectedTargets, true)
201}
202
203// SetBp2BuildTestRunner customizes the test fixture mechanism to run tests in Bp2Build mode.
Chris Parsons73f411b2023-06-20 21:46:57 +0000204var SetBp2BuildTestRunner = android.FixtureSetTestRunner(&bazelTestRunner{})
Paul Duffin4c0765a2022-10-29 17:48:00 +0100205
Chris Parsons73f411b2023-06-20 21:46:57 +0000206// bazelTestRunner customizes the test fixture mechanism to run tests of the bp2build build mode.
207type bazelTestRunner struct{}
Paul Duffin4c0765a2022-10-29 17:48:00 +0100208
209func (b *bazelTestRunner) FinalPreparer(result *android.TestResult) android.CustomTestResult {
210 ctx := result.TestContext
Chris Parsons73f411b2023-06-20 21:46:57 +0000211 ctx.RegisterForBazelConversion()
Paul Duffin4c0765a2022-10-29 17:48:00 +0100212
213 return &BazelTestResult{TestResult: result}
214}
215
216func (b *bazelTestRunner) PostParseProcessor(result android.CustomTestResult) {
217 bazelResult := result.(*BazelTestResult)
218 ctx := bazelResult.TestContext
219 config := bazelResult.Config
220 _, errs := ctx.ResolveDependencies(config)
221 if bazelResult.CollateErrs(errs) {
222 return
223 }
224
Chris Parsons73f411b2023-06-20 21:46:57 +0000225 codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "")
Paul Duffin4c0765a2022-10-29 17:48:00 +0100226 res, errs := GenerateBazelTargets(codegenCtx, false)
227 if bazelResult.CollateErrs(errs) {
228 return
229 }
230
231 // Store additional data for access by tests.
232 bazelResult.conversionResults = res
233}
234
235// BazelTestResult is a wrapper around android.TestResult to provide type safe access to the bazel
236// specific data stored by the bazelTestRunner.
237type BazelTestResult struct {
238 *android.TestResult
239
240 // The result returned by the GenerateBazelTargets function.
241 conversionResults
242}
243
244// CompareAllBazelTargets compares the BazelTargets produced by the test for all the directories
245// with the supplied set of expected targets.
246//
247// If ignoreUnexpected=false then this enforces an exact match where every BazelTarget produced must
248// have a corresponding expected BazelTarget.
249//
250// If ignoreUnexpected=true then it will ignore directories for which there are no expected targets.
251func (b BazelTestResult) CompareAllBazelTargets(t *testing.T, description string, expectedTargets map[string][]string, ignoreUnexpected bool) {
Liz Kammer2b3f56e2023-03-23 11:51:49 -0400252 t.Helper()
Paul Duffin4c0765a2022-10-29 17:48:00 +0100253 actualTargets := b.buildFileToTargets
254
255 // Generate the sorted set of directories to check.
Cole Faust18994c72023-02-28 16:02:16 -0800256 dirsToCheck := android.SortedKeys(expectedTargets)
Paul Duffin4c0765a2022-10-29 17:48:00 +0100257 if !ignoreUnexpected {
258 // This needs to perform an exact match so add the directories in which targets were
259 // produced to the list of directories to check.
Cole Faust18994c72023-02-28 16:02:16 -0800260 dirsToCheck = append(dirsToCheck, android.SortedKeys(actualTargets)...)
Paul Duffin4c0765a2022-10-29 17:48:00 +0100261 dirsToCheck = android.SortedUniqueStrings(dirsToCheck)
262 }
263
264 for _, dir := range dirsToCheck {
265 expected := expectedTargets[dir]
266 actual := actualTargets[dir]
267
268 if expected == nil {
269 if actual != nil {
270 t.Errorf("did not expect any bazel modules in %q but found %d", dir, len(actual))
271 }
272 } else if actual == nil {
273 expectedCount := len(expected)
274 if expectedCount > 0 {
275 t.Errorf("expected %d bazel modules in %q but did not find any", expectedCount, dir)
276 }
277 } else {
278 b.CompareBazelTargets(t, description, expected, actual)
279 }
280 }
281}
282
283func (b BazelTestResult) CompareBazelTargets(t *testing.T, description string, expectedContents []string, actualTargets BazelTargets) {
Liz Kammer748d7072023-01-25 12:07:43 -0500284 t.Helper()
Paul Duffin4c0765a2022-10-29 17:48:00 +0100285 if actualCount, expectedCount := len(actualTargets), len(expectedContents); actualCount != expectedCount {
Sasha Smundak9d2f1742022-08-04 13:28:38 -0700286 t.Errorf("%s: Expected %d bazel target (%s), got %d (%s)",
Paul Duffin4c0765a2022-10-29 17:48:00 +0100287 description, expectedCount, expectedContents, actualCount, actualTargets)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000288 } else {
Zi Wangfba0a212023-03-07 16:48:19 -0800289 sort.SliceStable(actualTargets, func(i, j int) bool {
290 return actualTargets[i].name < actualTargets[j].name
291 })
292 sort.SliceStable(expectedContents, func(i, j int) bool {
293 return getTargetName(expectedContents[i]) < getTargetName(expectedContents[j])
294 })
Paul Duffin4c0765a2022-10-29 17:48:00 +0100295 for i, actualTarget := range actualTargets {
296 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 +0000297 t.Errorf(
Paul Duffin4c0765a2022-10-29 17:48:00 +0100298 "%s[%d]: Expected generated Bazel target to be `%s`, got `%s`",
299 description, i, w, g)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000300 }
301 }
302 }
303}
304
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800305type nestedProps struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500306 Nested_prop *string
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800307}
308
Liz Kammer32a03392021-09-14 11:17:21 -0400309type EmbeddedProps struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500310 Embedded_prop *string
Liz Kammer32a03392021-09-14 11:17:21 -0400311}
312
313type OtherEmbeddedProps struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500314 Other_embedded_prop *string
Liz Kammer32a03392021-09-14 11:17:21 -0400315}
316
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800317type customProps struct {
Liz Kammer32a03392021-09-14 11:17:21 -0400318 EmbeddedProps
319 *OtherEmbeddedProps
320
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800321 Bool_prop bool
322 Bool_ptr_prop *bool
323 // 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 +0000324 Int_prop int `blueprint:"mutated"`
325 Int64_ptr_prop *int64
326 String_prop string
327 String_literal_prop *string `android:"arch_variant"`
328 String_ptr_prop *string
329 String_list_prop []string
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800330
331 Nested_props nestedProps
332 Nested_props_ptr *nestedProps
Liz Kammer4562a3b2021-04-21 18:15:34 -0400333
Liz Kammer32b77cf2021-08-04 15:17:02 -0400334 Arch_paths []string `android:"path,arch_variant"`
335 Arch_paths_exclude []string `android:"path,arch_variant"`
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400336
337 // Prop used to indicate this conversion should be 1 module -> multiple targets
338 One_to_many_prop *bool
Spandan Das5af0bd32022-09-28 20:43:08 +0000339
340 Api *string // File describing the APIs of this module
Spandan Das6a448ec2023-04-19 17:36:12 +0000341
342 Test_config_setting *bool // Used to test generation of config_setting targets
Spandan Das3131d672023-08-03 22:33:47 +0000343
344 Dir *string // Dir in which the Bazel Target will be created
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800345}
346
347type customModule struct {
348 android.ModuleBase
Liz Kammerea6666f2021-02-17 10:17:28 -0500349 android.BazelModuleBase
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800350
351 props customProps
352}
353
354// OutputFiles is needed because some instances of this module use dist with a
355// tag property which requires the module implements OutputFileProducer.
356func (m *customModule) OutputFiles(tag string) (android.Paths, error) {
357 return android.PathsForTesting("path" + tag), nil
358}
359
360func (m *customModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
361 // nothing for now.
362}
363
364func customModuleFactoryBase() android.Module {
365 module := &customModule{}
366 module.AddProperties(&module.props)
Liz Kammerea6666f2021-02-17 10:17:28 -0500367 android.InitBazelModule(module)
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800368 return module
369}
370
Liz Kammerdfeb1202022-05-13 17:20:20 -0400371func customModuleFactoryHostAndDevice() android.Module {
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800372 m := customModuleFactoryBase()
Liz Kammer4562a3b2021-04-21 18:15:34 -0400373 android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibBoth)
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800374 return m
375}
376
Liz Kammerdfeb1202022-05-13 17:20:20 -0400377func customModuleFactoryDeviceSupported() android.Module {
378 m := customModuleFactoryBase()
379 android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibBoth)
380 return m
381}
382
383func customModuleFactoryHostSupported() android.Module {
384 m := customModuleFactoryBase()
385 android.InitAndroidArchModule(m, android.HostSupported, android.MultilibBoth)
386 return m
387}
388
389func customModuleFactoryHostAndDeviceDefault() android.Module {
390 m := customModuleFactoryBase()
391 android.InitAndroidArchModule(m, android.HostAndDeviceDefault, android.MultilibBoth)
392 return m
393}
394
395func customModuleFactoryNeitherHostNorDeviceSupported() android.Module {
396 m := customModuleFactoryBase()
397 android.InitAndroidArchModule(m, android.NeitherHostNorDeviceSupported, android.MultilibBoth)
398 return m
399}
400
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800401type testProps struct {
402 Test_prop struct {
403 Test_string_prop string
404 }
405}
406
407type customTestModule struct {
408 android.ModuleBase
409
410 props customProps
411 test_props testProps
412}
413
414func (m *customTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
415 // nothing for now.
416}
417
418func customTestModuleFactoryBase() android.Module {
419 m := &customTestModule{}
420 m.AddProperties(&m.props)
421 m.AddProperties(&m.test_props)
422 return m
423}
424
425func customTestModuleFactory() android.Module {
426 m := customTestModuleFactoryBase()
427 android.InitAndroidModule(m)
428 return m
429}
430
431type customDefaultsModule struct {
432 android.ModuleBase
433 android.DefaultsModuleBase
434}
435
436func customDefaultsModuleFactoryBase() android.DefaultsModule {
437 module := &customDefaultsModule{}
438 module.AddProperties(&customProps{})
439 return module
440}
441
442func customDefaultsModuleFactoryBasic() android.Module {
443 return customDefaultsModuleFactoryBase()
444}
445
446func customDefaultsModuleFactory() android.Module {
447 m := customDefaultsModuleFactoryBase()
448 android.InitDefaultsModule(m)
449 return m
450}
Jingwen Chen73850672020-12-14 08:25:34 -0500451
Liz Kammer32a03392021-09-14 11:17:21 -0400452type EmbeddedAttr struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500453 Embedded_attr *string
Liz Kammer32a03392021-09-14 11:17:21 -0400454}
455
456type OtherEmbeddedAttr struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500457 Other_embedded_attr *string
Liz Kammer32a03392021-09-14 11:17:21 -0400458}
459
Jingwen Chen73850672020-12-14 08:25:34 -0500460type customBazelModuleAttributes struct {
Liz Kammer32a03392021-09-14 11:17:21 -0400461 EmbeddedAttr
462 *OtherEmbeddedAttr
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000463 String_literal_prop bazel.StringAttribute
464 String_ptr_prop *string
465 String_list_prop []string
466 Arch_paths bazel.LabelListAttribute
Spandan Das5af0bd32022-09-28 20:43:08 +0000467 Api bazel.LabelAttribute
Jingwen Chen73850672020-12-14 08:25:34 -0500468}
469
Spandan Das3131d672023-08-03 22:33:47 +0000470func (m *customModule) dir() *string {
471 return m.props.Dir
472}
473
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400474func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400475 if p := m.props.One_to_many_prop; p != nil && *p {
476 customBp2buildOneToMany(ctx, m)
477 return
478 }
Liz Kammer4562a3b2021-04-21 18:15:34 -0400479
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000480 paths := bazel.LabelListAttribute{}
481 strAttr := bazel.StringAttribute{}
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400482 for axis, configToProps := range m.GetArchVariantProperties(ctx, &customProps{}) {
483 for config, props := range configToProps {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000484 if custProps, ok := props.(*customProps); ok {
485 if custProps.Arch_paths != nil {
486 paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrcExcludes(ctx, custProps.Arch_paths, custProps.Arch_paths_exclude))
487 }
488 if custProps.String_literal_prop != nil {
489 strAttr.SetSelectValue(axis, config, custProps.String_literal_prop)
490 }
Liz Kammer4562a3b2021-04-21 18:15:34 -0400491 }
492 }
Jingwen Chen73850672020-12-14 08:25:34 -0500493 }
Cole Faust912bc882023-03-08 12:29:50 -0800494 productVariableProps := android.ProductVariableProperties(ctx, ctx.Module())
Liz Kammer9d2d4102022-12-21 14:51:37 -0500495 if props, ok := productVariableProps["String_literal_prop"]; ok {
496 for c, p := range props {
497 if val, ok := p.(*string); ok {
498 strAttr.SetSelectValue(c.ConfigurationAxis(), c.SelectKey(), val)
499 }
500 }
501 }
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400502
503 paths.ResolveExcludes()
504
505 attrs := &customBazelModuleAttributes{
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000506 String_literal_prop: strAttr,
507 String_ptr_prop: m.props.String_ptr_prop,
508 String_list_prop: m.props.String_list_prop,
509 Arch_paths: paths,
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400510 }
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000511
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400512 attrs.Embedded_attr = m.props.Embedded_prop
513 if m.props.OtherEmbeddedProps != nil {
514 attrs.OtherEmbeddedAttr = &OtherEmbeddedAttr{Other_embedded_attr: m.props.OtherEmbeddedProps.Other_embedded_prop}
515 }
516
517 props := bazel.BazelTargetModuleProperties{
518 Rule_class: "custom",
519 }
520
Spandan Das3131d672023-08-03 22:33:47 +0000521 ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name(), Dir: m.dir()}, attrs)
Spandan Das6a448ec2023-04-19 17:36:12 +0000522
523 if proptools.Bool(m.props.Test_config_setting) {
524 m.createConfigSetting(ctx)
525 }
526
527}
528
529func (m *customModule) createConfigSetting(ctx android.TopDownMutatorContext) {
530 csa := bazel.ConfigSettingAttributes{
531 Flag_values: bazel.StringMapAttribute{
532 "//build/bazel/rules/my_string_setting": m.Name(),
533 },
534 }
535 ca := android.CommonAttributes{
536 Name: m.Name() + "_config_setting",
537 }
538 ctx.CreateBazelConfigSetting(
539 csa,
540 ca,
541 ctx.ModuleDir(),
542 )
Jingwen Chen73850672020-12-14 08:25:34 -0500543}
Jingwen Chen40067de2021-01-26 21:58:43 -0500544
Spandan Das5af0bd32022-09-28 20:43:08 +0000545var _ android.ApiProvider = (*customModule)(nil)
546
547func (c *customModule) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
548 props := bazel.BazelTargetModuleProperties{
549 Rule_class: "custom_api_contribution",
550 }
551 apiAttribute := bazel.MakeLabelAttribute(
552 android.BazelLabelForModuleSrcSingle(ctx, proptools.String(c.props.Api)).Label,
553 )
554 attrs := &customBazelModuleAttributes{
555 Api: *apiAttribute,
556 }
557 ctx.CreateBazelTargetModule(props,
558 android.CommonAttributes{Name: c.Name()},
559 attrs)
560}
561
Jingwen Chen40067de2021-01-26 21:58:43 -0500562// A bp2build mutator that uses load statements and creates a 1:M mapping from
563// module to target.
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400564func customBp2buildOneToMany(ctx android.TopDownMutatorContext, m *customModule) {
Jingwen Chen77e8b7b2021-02-05 03:03:24 -0500565
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400566 baseName := m.Name()
567 attrs := &customBazelModuleAttributes{}
Jingwen Chen1fd14692021-02-05 03:01:50 -0500568
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400569 myLibraryProps := bazel.BazelTargetModuleProperties{
570 Rule_class: "my_library",
571 Bzl_load_location: "//build/bazel/rules:rules.bzl",
Jingwen Chen40067de2021-01-26 21:58:43 -0500572 }
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400573 ctx.CreateBazelTargetModule(myLibraryProps, android.CommonAttributes{Name: baseName}, attrs)
574
575 protoLibraryProps := bazel.BazelTargetModuleProperties{
576 Rule_class: "proto_library",
577 Bzl_load_location: "//build/bazel/rules:proto.bzl",
578 }
579 ctx.CreateBazelTargetModule(protoLibraryProps, android.CommonAttributes{Name: baseName + "_proto_library_deps"}, attrs)
580
581 myProtoLibraryProps := bazel.BazelTargetModuleProperties{
582 Rule_class: "my_proto_library",
583 Bzl_load_location: "//build/bazel/rules:proto.bzl",
584 }
585 ctx.CreateBazelTargetModule(myProtoLibraryProps, android.CommonAttributes{Name: baseName + "_my_proto_library_deps"}, attrs)
Jingwen Chen40067de2021-01-26 21:58:43 -0500586}
Jingwen Chenba369ad2021-02-22 10:19:34 -0500587
588// Helper method for tests to easily access the targets in a dir.
Liz Kammer6eff3232021-08-26 08:37:59 -0400589func generateBazelTargetsForDir(codegenCtx *CodegenContext, dir string) (BazelTargets, []error) {
Rupert Shuttleworth2a4fc3e2021-04-21 07:10:09 -0400590 // TODO: Set generateFilegroups to true and/or remove the generateFilegroups argument completely
Liz Kammer6eff3232021-08-26 08:37:59 -0400591 res, err := GenerateBazelTargets(codegenCtx, false)
Alix94e26032022-08-16 20:37:33 +0000592 if err != nil {
593 return BazelTargets{}, err
594 }
Liz Kammer6eff3232021-08-26 08:37:59 -0400595 return res.buildFileToTargets[dir], err
Jingwen Chenba369ad2021-02-22 10:19:34 -0500596}
Liz Kammer32b77cf2021-08-04 15:17:02 -0400597
598func registerCustomModuleForBp2buildConversion(ctx *android.TestContext) {
Liz Kammerdfeb1202022-05-13 17:20:20 -0400599 ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
Liz Kammer32b77cf2021-08-04 15:17:02 -0400600 ctx.RegisterForBazelConversion()
601}
Liz Kammer7a210ac2021-09-22 15:52:58 -0400602
603func simpleModuleDoNotConvertBp2build(typ, name string) string {
604 return fmt.Sprintf(`
605%s {
606 name: "%s",
607 bazel_module: { bp2build_available: false },
608}`, typ, name)
609}
Liz Kammer78cfdaa2021-11-08 12:56:31 -0500610
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000611type AttrNameToString map[string]string
Liz Kammer78cfdaa2021-11-08 12:56:31 -0500612
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000613func (a AttrNameToString) clone() AttrNameToString {
614 newAttrs := make(AttrNameToString, len(a))
Liz Kammerdfeb1202022-05-13 17:20:20 -0400615 for k, v := range a {
616 newAttrs[k] = v
617 }
618 return newAttrs
619}
620
621// makeBazelTargetNoRestrictions returns bazel target build file definition that can be host or
622// device specific, or independent of host/device.
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000623func makeBazelTargetHostOrDevice(typ, name string, attrs AttrNameToString, hod android.HostOrDeviceSupported) string {
Liz Kammerdfeb1202022-05-13 17:20:20 -0400624 if _, ok := attrs["target_compatible_with"]; !ok {
625 switch hod {
626 case android.HostSupported:
627 attrs["target_compatible_with"] = `select({
628 "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
629 "//conditions:default": [],
630 })`
631 case android.DeviceSupported:
632 attrs["target_compatible_with"] = `["//build/bazel/platforms/os:android"]`
633 }
634 }
635
Liz Kammer78cfdaa2021-11-08 12:56:31 -0500636 attrStrings := make([]string, 0, len(attrs)+1)
Sasha Smundakfb589492022-08-04 11:13:27 -0700637 if name != "" {
638 attrStrings = append(attrStrings, fmt.Sprintf(` name = "%s",`, name))
639 }
Cole Faust18994c72023-02-28 16:02:16 -0800640 for _, k := range android.SortedKeys(attrs) {
Liz Kammer78cfdaa2021-11-08 12:56:31 -0500641 attrStrings = append(attrStrings, fmt.Sprintf(" %s = %s,", k, attrs[k]))
642 }
643 return fmt.Sprintf(`%s(
644%s
645)`, typ, strings.Join(attrStrings, "\n"))
646}
Liz Kammerdfeb1202022-05-13 17:20:20 -0400647
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000648// MakeBazelTargetNoRestrictions returns bazel target build file definition that does not add a
Liz Kammerdfeb1202022-05-13 17:20:20 -0400649// target_compatible_with. This is useful for module types like filegroup and genrule that arch not
650// arch variant
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000651func MakeBazelTargetNoRestrictions(typ, name string, attrs AttrNameToString) string {
Liz Kammerdfeb1202022-05-13 17:20:20 -0400652 return makeBazelTargetHostOrDevice(typ, name, attrs, android.HostAndDeviceDefault)
653}
654
655// makeBazelTargetNoRestrictions returns bazel target build file definition that is device specific
656// as this is the most common default in Soong.
Alixe06d75b2022-08-31 18:28:19 +0000657func MakeBazelTarget(typ, name string, attrs AttrNameToString) string {
Liz Kammerdfeb1202022-05-13 17:20:20 -0400658 return makeBazelTargetHostOrDevice(typ, name, attrs, android.DeviceSupported)
659}
Sasha Smundak9d2f1742022-08-04 13:28:38 -0700660
661type ExpectedRuleTarget struct {
662 Rule string
663 Name string
664 Attrs AttrNameToString
665 Hod android.HostOrDeviceSupported
666}
667
668func (ebr ExpectedRuleTarget) String() string {
669 return makeBazelTargetHostOrDevice(ebr.Rule, ebr.Name, ebr.Attrs, ebr.Hod)
670}
Trevor Radcliffe087af542022-09-16 15:36:10 +0000671
672func makeCcStubSuiteTargets(name string, attrs AttrNameToString) string {
673 if _, hasStubs := attrs["stubs_symbol_file"]; !hasStubs {
674 return ""
675 }
676 STUB_SUITE_ATTRS := map[string]string{
Sam Delmerico5f906492023-03-15 18:06:18 -0400677 "stubs_symbol_file": "symbol_file",
678 "stubs_versions": "versions",
679 "soname": "soname",
680 "source_library_label": "source_library_label",
Trevor Radcliffe087af542022-09-16 15:36:10 +0000681 }
682
683 stubSuiteAttrs := AttrNameToString{}
684 for key, _ := range attrs {
685 if _, stubSuiteAttr := STUB_SUITE_ATTRS[key]; stubSuiteAttr {
686 stubSuiteAttrs[STUB_SUITE_ATTRS[key]] = attrs[key]
Sam Delmerico5f906492023-03-15 18:06:18 -0400687 } else {
688 panic(fmt.Sprintf("unused cc_stub_suite attr %q\n", key))
Trevor Radcliffe087af542022-09-16 15:36:10 +0000689 }
690 }
691 return MakeBazelTarget("cc_stub_suite", name+"_stub_libs", stubSuiteAttrs)
692}
Alix341484b2022-10-31 19:08:18 +0000693
694func MakeNeverlinkDuplicateTarget(moduleType string, name string) string {
Liz Kammer02914402023-08-07 13:38:18 -0400695 return MakeNeverlinkDuplicateTargetWithAttrs(moduleType, name, AttrNameToString{
696 "sdk_version": `"current"`, // use as default
697 })
Romain Jobredeaux2eef2e12023-02-24 12:07:08 -0500698}
699
700func MakeNeverlinkDuplicateTargetWithAttrs(moduleType string, name string, extraAttrs AttrNameToString) string {
701 attrs := extraAttrs
702 attrs["neverlink"] = `True`
703 attrs["exports"] = `[":` + name + `"]`
704 return MakeBazelTarget(moduleType, name+"-neverlink", attrs)
Alix341484b2022-10-31 19:08:18 +0000705}
Zi Wangfba0a212023-03-07 16:48:19 -0800706
707func getTargetName(targetContent string) string {
708 data := strings.Split(targetContent, "name = \"")
709 if len(data) < 2 {
710 return ""
711 } else {
712 endIndex := strings.Index(data[1], "\"")
713 return data[1][:endIndex]
714 }
715}