blob: b2804f9096ae497ff234d7aa43a9314ff91364ac [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"
Chris Parsonscd209032023-09-19 01:12:48 +000025 "regexp"
Zi Wangfba0a212023-03-07 16:48:19 -080026 "sort"
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000027 "strings"
Rupert Shuttleworth06559d02021-05-19 09:14:26 -040028 "testing"
29
Chris Parsons2173b5f2023-09-25 19:01:40 +000030 "android/soong/ui/metrics/bp2build_metrics_proto"
Spandan Das5af0bd32022-09-28 20:43:08 +000031 "github.com/google/blueprint/proptools"
32
Liz Kammer2dd9ca42020-11-25 16:06:39 -080033 "android/soong/android"
Sam Delmerico24c56032022-03-28 19:53:03 +000034 "android/soong/android/allowlists"
Jingwen Chen73850672020-12-14 08:25:34 -050035 "android/soong/bazel"
Liz Kammer2dd9ca42020-11-25 16:06:39 -080036)
37
Jingwen Chen91220d72021-03-24 02:18:33 -040038var (
Rupert Shuttleworth06559d02021-05-19 09:14:26 -040039 buildDir string
Jingwen Chen91220d72021-03-24 02:18:33 -040040)
41
Chris Parsonscd209032023-09-19 01:12:48 +000042var labelRegex = regexp.MustCompile(`^//([^: ]+):([^ ]+)$`)
43var simpleModuleNameRegex = regexp.MustCompile(`^[^: /]+$`)
44
Jingwen Chen5146ac02021-09-02 11:44:42 +000045func 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 +000046 t.Helper()
Jingwen Chen5146ac02021-09-02 11:44:42 +000047
Jingwen Chen5146ac02021-09-02 11:44:42 +000048 if len(errs) != 1 {
Liz Kammer6eff3232021-08-26 08:37:59 -040049 return false
Jingwen Chen5146ac02021-09-02 11:44:42 +000050 }
Liz Kammer54309532021-12-14 12:21:22 -050051 if strings.Contains(errs[0].Error(), expectedErr.Error()) {
Jingwen Chen5146ac02021-09-02 11:44:42 +000052 return true
53 }
54
55 return false
56}
57
Sam Delmerico3177a6e2022-06-21 19:28:33 +000058func errored(t *testing.T, tc Bp2buildTestCase, errs []error) bool {
Jingwen Chen5146ac02021-09-02 11:44:42 +000059 t.Helper()
Sam Delmerico3177a6e2022-06-21 19:28:33 +000060 if tc.ExpectedErr != nil {
Jingwen Chen5146ac02021-09-02 11:44:42 +000061 // Rely on checkErrors, as this test case is expected to have an error.
62 return false
63 }
64
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000065 if len(errs) > 0 {
66 for _, err := range errs {
Sam Delmerico3177a6e2022-06-21 19:28:33 +000067 t.Errorf("%s: %s", tc.Description, err)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000068 }
69 return true
70 }
Jingwen Chen5146ac02021-09-02 11:44:42 +000071
72 // All good, continue execution.
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000073 return false
74}
75
Trevor Radcliffe1b4b2d92022-09-01 18:57:01 +000076func RunBp2BuildTestCaseSimple(t *testing.T, tc Bp2buildTestCase) {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000077 t.Helper()
Sam Delmerico3177a6e2022-06-21 19:28:33 +000078 RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000079}
80
Sam Delmerico3177a6e2022-06-21 19:28:33 +000081type Bp2buildTestCase struct {
82 Description string
83 ModuleTypeUnderTest string
84 ModuleTypeUnderTestFactory android.ModuleFactory
Sam Delmerico5840afc2023-06-12 15:44:03 -040085 // Text to add to the toplevel, root Android.bp file. If Dir is not set, all
86 // ExpectedBazelTargets are assumed to be generated by this file.
Chris Parsons39a16972023-06-08 14:28:51 +000087 Blueprint string
Sam Delmerico5840afc2023-06-12 15:44:03 -040088 // ExpectedBazelTargets compares the BazelTargets generated in `Dir` (if not empty).
89 // Otherwise, it checks the BazelTargets generated by `Blueprint` in the root directory.
90 ExpectedBazelTargets []string
Chris Parsons2173b5f2023-09-25 19:01:40 +000091 // ExpectedConvertedModules asserts that modules in this list are labeled as "converted
92 // by bp2build" in the metrics reported by bp2build.
93 ExpectedConvertedModules []string
94 // ExpectedHandcraftedModules asserts that modules in this list are labeled as "handcrafted
95 // in build files" in the metrics reported by bp2build. Such modules are either explicitly
96 // defined in a BUILD file (by name), or registered as "otherwise implicitly handled"
97 // by bp2build (for example, by macros owned by other modules).
98 ExpectedHandcraftedModules []string
99
Chris Parsons5011e612023-09-13 23:33:20 +0000100 // AlreadyExistingBuildContents, if non-empty, simulates an already-present source BUILD file
101 // in the directory under test. The BUILD file has the given contents. This BUILD file
102 // will also be treated as "BUILD file to keep" by the simulated bp2build environment.
103 AlreadyExistingBuildContents string
Chris Parsonscd209032023-09-19 01:12:48 +0000104
105 // StubbedBuildDefinitions, if non-empty, adds stub definitions to already-present source
106 // BUILD files for each bazel label given. The BUILD files with these stub definitions
107 // are added to the BUILD file given in AlreadyExistingBuildContents.
108 // Labels may be of the form //pkg/to:target_name (which would be defined in pkg/to/BUILD.bazel)
109 // or `target_name` (which would be defined in ./BUILD.bazel).
Chris Parsons5011e612023-09-13 23:33:20 +0000110 StubbedBuildDefinitions []string
111
112 Filesystem map[string]string
Sam Delmerico5840afc2023-06-12 15:44:03 -0400113 // Dir sets the directory which will be compared against the targets in ExpectedBazelTargets.
114 // This should used in conjunction with the Filesystem property to check for targets
115 // generated from a directory that is not the root.
116 // If not set, all ExpectedBazelTargets are assumed to be generated by the text in the
117 // Blueprint property.
118 Dir string
Trevor Radcliffe58ea4512022-04-07 20:36:39 +0000119 // An error with a string contained within the string of the expected error
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000120 ExpectedErr error
121 UnconvertedDepsMode unconvertedDepsMode
Jingwen Chen0eeaeb82022-09-21 10:27:42 +0000122
123 // For every directory listed here, the BUILD file for that directory will
124 // be merged with the generated BUILD file. This allows custom BUILD targets
125 // to be used in tests, or use BUILD files to draw package boundaries.
126 KeepBuildFileForDirs []string
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000127}
128
Chris Parsons2173b5f2023-09-25 19:01:40 +0000129func RunBp2BuildTestCaseExtraContext(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), modifyContext func(ctx *android.TestContext), tc Bp2buildTestCase) {
130 t.Helper()
Chris Parsons5f1b3c72023-09-28 20:41:03 +0000131 preparers := []android.FixturePreparer{
Chris Parsons2173b5f2023-09-25 19:01:40 +0000132 android.FixtureRegisterWithContext(registerModuleTypes),
Chris Parsons5f1b3c72023-09-28 20:41:03 +0000133 }
134 if modifyContext != nil {
135 preparers = append(preparers, android.FixtureModifyContext(modifyContext))
136 }
Chris Parsons5f1b3c72023-09-28 20:41:03 +0000137 preparers = append(preparers, SetBp2BuildTestRunner)
138 bp2buildSetup := android.GroupFixturePreparers(
139 preparers...,
Chris Parsons2173b5f2023-09-25 19:01:40 +0000140 )
141 runBp2BuildTestCaseWithSetup(t, bp2buildSetup, tc)
142}
143
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000144func RunBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
Liz Kammerffc17e42022-11-23 09:42:05 -0500145 t.Helper()
Chris Parsons5f1b3c72023-09-28 20:41:03 +0000146 RunBp2BuildTestCaseExtraContext(t, registerModuleTypes, nil, tc)
Spandan Das5af0bd32022-09-28 20:43:08 +0000147}
148
Paul Duffin4c0765a2022-10-29 17:48:00 +0100149func 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 +0000150 t.Helper()
Chris Parsonscd209032023-09-19 01:12:48 +0000151 if tc.Filesystem == nil {
152 tc.Filesystem = map[string]string{}
153 }
Chris Parsons5011e612023-09-13 23:33:20 +0000154 checkDir := "."
155 if tc.Dir != "" {
156 checkDir = tc.Dir
157 }
158 keepExistingBuildDirs := tc.KeepBuildFileForDirs
159 buildFilesToParse := []string{}
Chris Parsonscd209032023-09-19 01:12:48 +0000160
161 if len(tc.StubbedBuildDefinitions) > 0 {
162 for _, buildDef := range tc.StubbedBuildDefinitions {
163 globalLabelMatch := labelRegex.FindStringSubmatch(buildDef)
164 var dir, targetName string
165 if len(globalLabelMatch) > 0 {
166 dir = globalLabelMatch[1]
167 targetName = globalLabelMatch[2]
168 } else {
169 if !simpleModuleNameRegex.MatchString(buildDef) {
170 t.Errorf("Stubbed build definition '%s' must be either a simple module name or of global target syntax (//foo/bar:baz).", buildDef)
171 return
172 }
173 dir = "."
174 targetName = buildDef
175 }
176 buildFilePath := filepath.Join(dir, "BUILD")
177 tc.Filesystem[buildFilePath] +=
178 MakeBazelTarget(
179 "bp2build_test_stub",
180 targetName,
181 AttrNameToString{})
182 keepExistingBuildDirs = append(keepExistingBuildDirs, dir)
183 buildFilesToParse = append(buildFilesToParse, buildFilePath)
184 }
185 }
186 if len(tc.AlreadyExistingBuildContents) > 0 {
187 buildFilePath := filepath.Join(checkDir, "BUILD")
188 tc.Filesystem[buildFilePath] += tc.AlreadyExistingBuildContents
189 keepExistingBuildDirs = append(keepExistingBuildDirs, checkDir)
190 buildFilesToParse = append(buildFilesToParse, buildFilePath)
191 }
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000192 filesystem := make(map[string][]byte)
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000193 for f, content := range tc.Filesystem {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000194 filesystem[f] = []byte(content)
195 }
Paul Duffin4c0765a2022-10-29 17:48:00 +0100196 preparers := []android.FixturePreparer{
197 extraPreparer,
198 android.FixtureMergeMockFs(filesystem),
199 android.FixtureWithRootAndroidBp(tc.Blueprint),
200 android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
201 ctx.RegisterModuleType(tc.ModuleTypeUnderTest, tc.ModuleTypeUnderTestFactory)
202 }),
Chris Parsons5011e612023-09-13 23:33:20 +0000203 android.FixtureModifyContextWithMockFs(func(ctx *android.TestContext) {
Paul Duffin4c0765a2022-10-29 17:48:00 +0100204 // A default configuration for tests to not have to specify bp2build_available on top level
205 // targets.
206 bp2buildConfig := android.NewBp2BuildAllowlist().SetDefaultConfig(
207 allowlists.Bp2BuildConfig{
208 android.Bp2BuildTopLevel: allowlists.Bp2BuildDefaultTrueRecursively,
209 },
210 )
Chris Parsons5011e612023-09-13 23:33:20 +0000211 for _, f := range keepExistingBuildDirs {
Paul Duffin4c0765a2022-10-29 17:48:00 +0100212 bp2buildConfig.SetKeepExistingBuildFile(map[string]bool{
213 f: /*recursive=*/ false,
214 })
215 }
216 ctx.RegisterBp2BuildConfig(bp2buildConfig)
Chris Parsons39a16972023-06-08 14:28:51 +0000217 // This setting is added to bp2build invocations. It prevents bp2build
218 // from cloning modules to their original state after mutators run. This
219 // would lose some data intentionally set by these mutators.
220 ctx.SkipCloneModulesAfterMutators = true
Chris Parsons5011e612023-09-13 23:33:20 +0000221 err := ctx.RegisterExistingBazelTargets(".", buildFilesToParse)
222 if err != nil {
223 t.Errorf("error parsing build files in test setup: %s", err)
224 }
Paul Duffin4c0765a2022-10-29 17:48:00 +0100225 }),
226 android.FixtureModifyEnv(func(env map[string]string) {
227 if tc.UnconvertedDepsMode == errorModulesUnconvertedDeps {
228 env["BP2BUILD_ERROR_UNCONVERTED"] = "true"
229 }
230 }),
Jingwen Chen5146ac02021-09-02 11:44:42 +0000231 }
232
Paul Duffin4c0765a2022-10-29 17:48:00 +0100233 preparer := android.GroupFixturePreparers(preparers...)
234 if tc.ExpectedErr != nil {
235 pattern := "\\Q" + tc.ExpectedErr.Error() + "\\E"
236 preparer = preparer.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(pattern))
237 }
238 result := preparer.RunTestWithCustomResult(t).(*BazelTestResult)
239 if len(result.Errs) > 0 {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000240 return
241 }
242
Paul Duffin4c0765a2022-10-29 17:48:00 +0100243 expectedTargets := map[string][]string{
244 checkDir: tc.ExpectedBazelTargets,
Liz Kammer6eff3232021-08-26 08:37:59 -0400245 }
Paul Duffin4c0765a2022-10-29 17:48:00 +0100246
Chris Parsons2173b5f2023-09-25 19:01:40 +0000247 result.CompareAllBazelTargets(t, tc, expectedTargets, true)
Paul Duffin4c0765a2022-10-29 17:48:00 +0100248}
249
250// SetBp2BuildTestRunner customizes the test fixture mechanism to run tests in Bp2Build mode.
Chris Parsons73f411b2023-06-20 21:46:57 +0000251var SetBp2BuildTestRunner = android.FixtureSetTestRunner(&bazelTestRunner{})
Paul Duffin4c0765a2022-10-29 17:48:00 +0100252
Chris Parsons73f411b2023-06-20 21:46:57 +0000253// bazelTestRunner customizes the test fixture mechanism to run tests of the bp2build build mode.
254type bazelTestRunner struct{}
Paul Duffin4c0765a2022-10-29 17:48:00 +0100255
256func (b *bazelTestRunner) FinalPreparer(result *android.TestResult) android.CustomTestResult {
257 ctx := result.TestContext
Chris Parsons73f411b2023-06-20 21:46:57 +0000258 ctx.RegisterForBazelConversion()
Paul Duffin4c0765a2022-10-29 17:48:00 +0100259
260 return &BazelTestResult{TestResult: result}
261}
262
263func (b *bazelTestRunner) PostParseProcessor(result android.CustomTestResult) {
264 bazelResult := result.(*BazelTestResult)
265 ctx := bazelResult.TestContext
266 config := bazelResult.Config
267 _, errs := ctx.ResolveDependencies(config)
268 if bazelResult.CollateErrs(errs) {
269 return
270 }
271
Chris Parsons73f411b2023-06-20 21:46:57 +0000272 codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "")
Paul Duffin4c0765a2022-10-29 17:48:00 +0100273 res, errs := GenerateBazelTargets(codegenCtx, false)
274 if bazelResult.CollateErrs(errs) {
275 return
276 }
277
278 // Store additional data for access by tests.
279 bazelResult.conversionResults = res
280}
281
282// BazelTestResult is a wrapper around android.TestResult to provide type safe access to the bazel
283// specific data stored by the bazelTestRunner.
284type BazelTestResult struct {
285 *android.TestResult
286
287 // The result returned by the GenerateBazelTargets function.
288 conversionResults
289}
290
291// CompareAllBazelTargets compares the BazelTargets produced by the test for all the directories
292// with the supplied set of expected targets.
293//
294// If ignoreUnexpected=false then this enforces an exact match where every BazelTarget produced must
295// have a corresponding expected BazelTarget.
296//
297// If ignoreUnexpected=true then it will ignore directories for which there are no expected targets.
Chris Parsons2173b5f2023-09-25 19:01:40 +0000298func (b BazelTestResult) CompareAllBazelTargets(t *testing.T, tc Bp2buildTestCase, expectedTargets map[string][]string, ignoreUnexpected bool) {
Liz Kammer2b3f56e2023-03-23 11:51:49 -0400299 t.Helper()
Paul Duffin4c0765a2022-10-29 17:48:00 +0100300 actualTargets := b.buildFileToTargets
301
302 // Generate the sorted set of directories to check.
Cole Faust18994c72023-02-28 16:02:16 -0800303 dirsToCheck := android.SortedKeys(expectedTargets)
Paul Duffin4c0765a2022-10-29 17:48:00 +0100304 if !ignoreUnexpected {
305 // This needs to perform an exact match so add the directories in which targets were
306 // produced to the list of directories to check.
Cole Faust18994c72023-02-28 16:02:16 -0800307 dirsToCheck = append(dirsToCheck, android.SortedKeys(actualTargets)...)
Paul Duffin4c0765a2022-10-29 17:48:00 +0100308 dirsToCheck = android.SortedUniqueStrings(dirsToCheck)
309 }
310
311 for _, dir := range dirsToCheck {
312 expected := expectedTargets[dir]
313 actual := actualTargets[dir]
314
315 if expected == nil {
316 if actual != nil {
317 t.Errorf("did not expect any bazel modules in %q but found %d", dir, len(actual))
318 }
319 } else if actual == nil {
320 expectedCount := len(expected)
321 if expectedCount > 0 {
322 t.Errorf("expected %d bazel modules in %q but did not find any", expectedCount, dir)
323 }
324 } else {
Chris Parsons2173b5f2023-09-25 19:01:40 +0000325 b.CompareBazelTargets(t, tc.Description, expected, actual)
326 }
327 }
328
329 for _, module := range tc.ExpectedConvertedModules {
330 if _, found := b.metrics.convertedModulePathMap[module]; !found {
331 t.Errorf("expected %s to be generated by bp2build, but was not. Map of converted modules: %s", module, b.metrics.convertedModulePathMap)
332 }
333 }
334
335 for _, module := range tc.ExpectedHandcraftedModules {
336 if reason, found := b.metrics.serialized.UnconvertedModules[module]; !found {
337 t.Errorf("expected %s to be marked 'unconverted' by bp2build, but was not found. Full list: %s",
338 module, b.metrics.serialized.UnconvertedModules)
339 } else {
340 if reason.Type != bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE {
341 t.Errorf("expected %s to be marked 'handcrafted' by bp2build, but was disabled for another reason: %s", module, reason)
342 }
Paul Duffin4c0765a2022-10-29 17:48:00 +0100343 }
344 }
345}
346
347func (b BazelTestResult) CompareBazelTargets(t *testing.T, description string, expectedContents []string, actualTargets BazelTargets) {
Liz Kammer748d7072023-01-25 12:07:43 -0500348 t.Helper()
Paul Duffin4c0765a2022-10-29 17:48:00 +0100349 if actualCount, expectedCount := len(actualTargets), len(expectedContents); actualCount != expectedCount {
Sasha Smundak9d2f1742022-08-04 13:28:38 -0700350 t.Errorf("%s: Expected %d bazel target (%s), got %d (%s)",
Paul Duffin4c0765a2022-10-29 17:48:00 +0100351 description, expectedCount, expectedContents, actualCount, actualTargets)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000352 } else {
Zi Wangfba0a212023-03-07 16:48:19 -0800353 sort.SliceStable(actualTargets, func(i, j int) bool {
354 return actualTargets[i].name < actualTargets[j].name
355 })
356 sort.SliceStable(expectedContents, func(i, j int) bool {
357 return getTargetName(expectedContents[i]) < getTargetName(expectedContents[j])
358 })
Paul Duffin4c0765a2022-10-29 17:48:00 +0100359 for i, actualTarget := range actualTargets {
360 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 +0000361 t.Errorf(
Paul Duffin4c0765a2022-10-29 17:48:00 +0100362 "%s[%d]: Expected generated Bazel target to be `%s`, got `%s`",
363 description, i, w, g)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000364 }
365 }
366 }
367}
368
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800369type nestedProps struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500370 Nested_prop *string
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800371}
372
Liz Kammer32a03392021-09-14 11:17:21 -0400373type EmbeddedProps struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500374 Embedded_prop *string
Liz Kammer32a03392021-09-14 11:17:21 -0400375}
376
377type OtherEmbeddedProps struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500378 Other_embedded_prop *string
Liz Kammer32a03392021-09-14 11:17:21 -0400379}
380
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800381type customProps struct {
Liz Kammer32a03392021-09-14 11:17:21 -0400382 EmbeddedProps
383 *OtherEmbeddedProps
384
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800385 Bool_prop bool
386 Bool_ptr_prop *bool
387 // 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 +0000388 Int_prop int `blueprint:"mutated"`
389 Int64_ptr_prop *int64
390 String_prop string
391 String_literal_prop *string `android:"arch_variant"`
392 String_ptr_prop *string
393 String_list_prop []string
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800394
395 Nested_props nestedProps
396 Nested_props_ptr *nestedProps
Liz Kammer4562a3b2021-04-21 18:15:34 -0400397
Liz Kammer32b77cf2021-08-04 15:17:02 -0400398 Arch_paths []string `android:"path,arch_variant"`
399 Arch_paths_exclude []string `android:"path,arch_variant"`
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400400
401 // Prop used to indicate this conversion should be 1 module -> multiple targets
402 One_to_many_prop *bool
Spandan Das5af0bd32022-09-28 20:43:08 +0000403
Chris Parsons5f1b3c72023-09-28 20:41:03 +0000404 // Prop used to simulate an unsupported property in bp2build conversion. If this
405 // is true, this module should be treated as "unconvertible" via bp2build.
406 Does_not_convert_to_bazel *bool
407
Spandan Das5af0bd32022-09-28 20:43:08 +0000408 Api *string // File describing the APIs of this module
Spandan Das6a448ec2023-04-19 17:36:12 +0000409
410 Test_config_setting *bool // Used to test generation of config_setting targets
Spandan Das3131d672023-08-03 22:33:47 +0000411
412 Dir *string // Dir in which the Bazel Target will be created
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800413}
414
415type customModule struct {
416 android.ModuleBase
Liz Kammerea6666f2021-02-17 10:17:28 -0500417 android.BazelModuleBase
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800418
419 props customProps
420}
421
422// OutputFiles is needed because some instances of this module use dist with a
423// tag property which requires the module implements OutputFileProducer.
424func (m *customModule) OutputFiles(tag string) (android.Paths, error) {
425 return android.PathsForTesting("path" + tag), nil
426}
427
428func (m *customModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
429 // nothing for now.
430}
431
432func customModuleFactoryBase() android.Module {
433 module := &customModule{}
434 module.AddProperties(&module.props)
Liz Kammerea6666f2021-02-17 10:17:28 -0500435 android.InitBazelModule(module)
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800436 return module
437}
438
Liz Kammerdfeb1202022-05-13 17:20:20 -0400439func customModuleFactoryHostAndDevice() android.Module {
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800440 m := customModuleFactoryBase()
Liz Kammer4562a3b2021-04-21 18:15:34 -0400441 android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibBoth)
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800442 return m
443}
444
Liz Kammerdfeb1202022-05-13 17:20:20 -0400445func customModuleFactoryDeviceSupported() android.Module {
446 m := customModuleFactoryBase()
447 android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibBoth)
448 return m
449}
450
451func customModuleFactoryHostSupported() android.Module {
452 m := customModuleFactoryBase()
453 android.InitAndroidArchModule(m, android.HostSupported, android.MultilibBoth)
454 return m
455}
456
457func customModuleFactoryHostAndDeviceDefault() android.Module {
458 m := customModuleFactoryBase()
459 android.InitAndroidArchModule(m, android.HostAndDeviceDefault, android.MultilibBoth)
460 return m
461}
462
463func customModuleFactoryNeitherHostNorDeviceSupported() android.Module {
464 m := customModuleFactoryBase()
465 android.InitAndroidArchModule(m, android.NeitherHostNorDeviceSupported, android.MultilibBoth)
466 return m
467}
468
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800469type testProps struct {
470 Test_prop struct {
471 Test_string_prop string
472 }
473}
474
475type customTestModule struct {
476 android.ModuleBase
477
478 props customProps
479 test_props testProps
480}
481
482func (m *customTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
483 // nothing for now.
484}
485
486func customTestModuleFactoryBase() android.Module {
487 m := &customTestModule{}
488 m.AddProperties(&m.props)
489 m.AddProperties(&m.test_props)
490 return m
491}
492
493func customTestModuleFactory() android.Module {
494 m := customTestModuleFactoryBase()
495 android.InitAndroidModule(m)
496 return m
497}
498
499type customDefaultsModule struct {
500 android.ModuleBase
501 android.DefaultsModuleBase
502}
503
504func customDefaultsModuleFactoryBase() android.DefaultsModule {
505 module := &customDefaultsModule{}
506 module.AddProperties(&customProps{})
507 return module
508}
509
510func customDefaultsModuleFactoryBasic() android.Module {
511 return customDefaultsModuleFactoryBase()
512}
513
514func customDefaultsModuleFactory() android.Module {
515 m := customDefaultsModuleFactoryBase()
516 android.InitDefaultsModule(m)
517 return m
518}
Jingwen Chen73850672020-12-14 08:25:34 -0500519
Liz Kammer32a03392021-09-14 11:17:21 -0400520type EmbeddedAttr struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500521 Embedded_attr *string
Liz Kammer32a03392021-09-14 11:17:21 -0400522}
523
524type OtherEmbeddedAttr struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500525 Other_embedded_attr *string
Liz Kammer32a03392021-09-14 11:17:21 -0400526}
527
Jingwen Chen73850672020-12-14 08:25:34 -0500528type customBazelModuleAttributes struct {
Liz Kammer32a03392021-09-14 11:17:21 -0400529 EmbeddedAttr
530 *OtherEmbeddedAttr
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000531 String_literal_prop bazel.StringAttribute
532 String_ptr_prop *string
533 String_list_prop []string
534 Arch_paths bazel.LabelListAttribute
Spandan Das5af0bd32022-09-28 20:43:08 +0000535 Api bazel.LabelAttribute
Jingwen Chen73850672020-12-14 08:25:34 -0500536}
537
Spandan Das3131d672023-08-03 22:33:47 +0000538func (m *customModule) dir() *string {
539 return m.props.Dir
540}
541
Chris Parsons637458d2023-09-19 20:09:00 +0000542func (m *customModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
Chris Parsons5f1b3c72023-09-28 20:41:03 +0000543 if p := m.props.Does_not_convert_to_bazel; p != nil && *p {
544 ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "")
545 return
546 }
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400547 if p := m.props.One_to_many_prop; p != nil && *p {
548 customBp2buildOneToMany(ctx, m)
549 return
550 }
Liz Kammer4562a3b2021-04-21 18:15:34 -0400551
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000552 paths := bazel.LabelListAttribute{}
553 strAttr := bazel.StringAttribute{}
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400554 for axis, configToProps := range m.GetArchVariantProperties(ctx, &customProps{}) {
555 for config, props := range configToProps {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000556 if custProps, ok := props.(*customProps); ok {
557 if custProps.Arch_paths != nil {
558 paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrcExcludes(ctx, custProps.Arch_paths, custProps.Arch_paths_exclude))
559 }
560 if custProps.String_literal_prop != nil {
561 strAttr.SetSelectValue(axis, config, custProps.String_literal_prop)
562 }
Liz Kammer4562a3b2021-04-21 18:15:34 -0400563 }
564 }
Jingwen Chen73850672020-12-14 08:25:34 -0500565 }
Liz Kammer9e2a5a72023-09-19 08:41:14 -0400566 productVariableProps, errs := android.ProductVariableProperties(ctx, ctx.Module())
567 for _, err := range errs {
568 ctx.ModuleErrorf("ProductVariableProperties error: %s", err)
569 }
Liz Kammer9d2d4102022-12-21 14:51:37 -0500570 if props, ok := productVariableProps["String_literal_prop"]; ok {
571 for c, p := range props {
572 if val, ok := p.(*string); ok {
573 strAttr.SetSelectValue(c.ConfigurationAxis(), c.SelectKey(), val)
574 }
575 }
576 }
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400577
578 paths.ResolveExcludes()
579
580 attrs := &customBazelModuleAttributes{
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000581 String_literal_prop: strAttr,
582 String_ptr_prop: m.props.String_ptr_prop,
583 String_list_prop: m.props.String_list_prop,
584 Arch_paths: paths,
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400585 }
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000586
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400587 attrs.Embedded_attr = m.props.Embedded_prop
588 if m.props.OtherEmbeddedProps != nil {
589 attrs.OtherEmbeddedAttr = &OtherEmbeddedAttr{Other_embedded_attr: m.props.OtherEmbeddedProps.Other_embedded_prop}
590 }
591
592 props := bazel.BazelTargetModuleProperties{
593 Rule_class: "custom",
594 }
595
Spandan Das3131d672023-08-03 22:33:47 +0000596 ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name(), Dir: m.dir()}, attrs)
Spandan Das6a448ec2023-04-19 17:36:12 +0000597
598 if proptools.Bool(m.props.Test_config_setting) {
599 m.createConfigSetting(ctx)
600 }
601
602}
603
Chris Parsons637458d2023-09-19 20:09:00 +0000604func (m *customModule) createConfigSetting(ctx android.Bp2buildMutatorContext) {
Spandan Das6a448ec2023-04-19 17:36:12 +0000605 csa := bazel.ConfigSettingAttributes{
606 Flag_values: bazel.StringMapAttribute{
607 "//build/bazel/rules/my_string_setting": m.Name(),
608 },
609 }
610 ca := android.CommonAttributes{
611 Name: m.Name() + "_config_setting",
612 }
613 ctx.CreateBazelConfigSetting(
614 csa,
615 ca,
616 ctx.ModuleDir(),
617 )
Jingwen Chen73850672020-12-14 08:25:34 -0500618}
Jingwen Chen40067de2021-01-26 21:58:43 -0500619
620// A bp2build mutator that uses load statements and creates a 1:M mapping from
621// module to target.
Chris Parsons637458d2023-09-19 20:09:00 +0000622func customBp2buildOneToMany(ctx android.Bp2buildMutatorContext, m *customModule) {
Jingwen Chen77e8b7b2021-02-05 03:03:24 -0500623
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400624 baseName := m.Name()
625 attrs := &customBazelModuleAttributes{}
Jingwen Chen1fd14692021-02-05 03:01:50 -0500626
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400627 myLibraryProps := bazel.BazelTargetModuleProperties{
628 Rule_class: "my_library",
629 Bzl_load_location: "//build/bazel/rules:rules.bzl",
Jingwen Chen40067de2021-01-26 21:58:43 -0500630 }
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400631 ctx.CreateBazelTargetModule(myLibraryProps, android.CommonAttributes{Name: baseName}, attrs)
632
633 protoLibraryProps := bazel.BazelTargetModuleProperties{
634 Rule_class: "proto_library",
635 Bzl_load_location: "//build/bazel/rules:proto.bzl",
636 }
637 ctx.CreateBazelTargetModule(protoLibraryProps, android.CommonAttributes{Name: baseName + "_proto_library_deps"}, attrs)
638
639 myProtoLibraryProps := bazel.BazelTargetModuleProperties{
640 Rule_class: "my_proto_library",
641 Bzl_load_location: "//build/bazel/rules:proto.bzl",
642 }
643 ctx.CreateBazelTargetModule(myProtoLibraryProps, android.CommonAttributes{Name: baseName + "_my_proto_library_deps"}, attrs)
Jingwen Chen40067de2021-01-26 21:58:43 -0500644}
Jingwen Chenba369ad2021-02-22 10:19:34 -0500645
646// Helper method for tests to easily access the targets in a dir.
Liz Kammer6eff3232021-08-26 08:37:59 -0400647func generateBazelTargetsForDir(codegenCtx *CodegenContext, dir string) (BazelTargets, []error) {
Rupert Shuttleworth2a4fc3e2021-04-21 07:10:09 -0400648 // TODO: Set generateFilegroups to true and/or remove the generateFilegroups argument completely
Liz Kammer6eff3232021-08-26 08:37:59 -0400649 res, err := GenerateBazelTargets(codegenCtx, false)
Alix94e26032022-08-16 20:37:33 +0000650 if err != nil {
651 return BazelTargets{}, err
652 }
Liz Kammer6eff3232021-08-26 08:37:59 -0400653 return res.buildFileToTargets[dir], err
Jingwen Chenba369ad2021-02-22 10:19:34 -0500654}
Liz Kammer32b77cf2021-08-04 15:17:02 -0400655
656func registerCustomModuleForBp2buildConversion(ctx *android.TestContext) {
Liz Kammerdfeb1202022-05-13 17:20:20 -0400657 ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
Liz Kammer32b77cf2021-08-04 15:17:02 -0400658 ctx.RegisterForBazelConversion()
659}
Liz Kammer7a210ac2021-09-22 15:52:58 -0400660
Chris Parsonscd209032023-09-19 01:12:48 +0000661func simpleModule(typ, name string) string {
Liz Kammer7a210ac2021-09-22 15:52:58 -0400662 return fmt.Sprintf(`
663%s {
664 name: "%s",
Liz Kammer7a210ac2021-09-22 15:52:58 -0400665}`, typ, name)
666}
Liz Kammer78cfdaa2021-11-08 12:56:31 -0500667
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000668type AttrNameToString map[string]string
Liz Kammer78cfdaa2021-11-08 12:56:31 -0500669
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000670func (a AttrNameToString) clone() AttrNameToString {
671 newAttrs := make(AttrNameToString, len(a))
Liz Kammerdfeb1202022-05-13 17:20:20 -0400672 for k, v := range a {
673 newAttrs[k] = v
674 }
675 return newAttrs
676}
677
678// makeBazelTargetNoRestrictions returns bazel target build file definition that can be host or
679// device specific, or independent of host/device.
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000680func makeBazelTargetHostOrDevice(typ, name string, attrs AttrNameToString, hod android.HostOrDeviceSupported) string {
Liz Kammerdfeb1202022-05-13 17:20:20 -0400681 if _, ok := attrs["target_compatible_with"]; !ok {
682 switch hod {
683 case android.HostSupported:
684 attrs["target_compatible_with"] = `select({
Jingwen Chen9c2e3ee2023-10-11 10:51:28 +0000685 "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
Liz Kammerdfeb1202022-05-13 17:20:20 -0400686 "//conditions:default": [],
687 })`
688 case android.DeviceSupported:
Jingwen Chen9c2e3ee2023-10-11 10:51:28 +0000689 attrs["target_compatible_with"] = `["//build/bazel_common_rules/platforms/os:android"]`
Liz Kammerdfeb1202022-05-13 17:20:20 -0400690 }
691 }
692
Liz Kammer78cfdaa2021-11-08 12:56:31 -0500693 attrStrings := make([]string, 0, len(attrs)+1)
Sasha Smundakfb589492022-08-04 11:13:27 -0700694 if name != "" {
695 attrStrings = append(attrStrings, fmt.Sprintf(` name = "%s",`, name))
696 }
Cole Faust18994c72023-02-28 16:02:16 -0800697 for _, k := range android.SortedKeys(attrs) {
Liz Kammer78cfdaa2021-11-08 12:56:31 -0500698 attrStrings = append(attrStrings, fmt.Sprintf(" %s = %s,", k, attrs[k]))
699 }
700 return fmt.Sprintf(`%s(
701%s
702)`, typ, strings.Join(attrStrings, "\n"))
703}
Liz Kammerdfeb1202022-05-13 17:20:20 -0400704
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000705// MakeBazelTargetNoRestrictions returns bazel target build file definition that does not add a
Liz Kammerdfeb1202022-05-13 17:20:20 -0400706// target_compatible_with. This is useful for module types like filegroup and genrule that arch not
707// arch variant
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000708func MakeBazelTargetNoRestrictions(typ, name string, attrs AttrNameToString) string {
Liz Kammerdfeb1202022-05-13 17:20:20 -0400709 return makeBazelTargetHostOrDevice(typ, name, attrs, android.HostAndDeviceDefault)
710}
711
712// makeBazelTargetNoRestrictions returns bazel target build file definition that is device specific
713// as this is the most common default in Soong.
Alixe06d75b2022-08-31 18:28:19 +0000714func MakeBazelTarget(typ, name string, attrs AttrNameToString) string {
Liz Kammerdfeb1202022-05-13 17:20:20 -0400715 return makeBazelTargetHostOrDevice(typ, name, attrs, android.DeviceSupported)
716}
Sasha Smundak9d2f1742022-08-04 13:28:38 -0700717
718type ExpectedRuleTarget struct {
719 Rule string
720 Name string
721 Attrs AttrNameToString
722 Hod android.HostOrDeviceSupported
723}
724
725func (ebr ExpectedRuleTarget) String() string {
726 return makeBazelTargetHostOrDevice(ebr.Rule, ebr.Name, ebr.Attrs, ebr.Hod)
727}
Trevor Radcliffe087af542022-09-16 15:36:10 +0000728
729func makeCcStubSuiteTargets(name string, attrs AttrNameToString) string {
730 if _, hasStubs := attrs["stubs_symbol_file"]; !hasStubs {
731 return ""
732 }
733 STUB_SUITE_ATTRS := map[string]string{
Spandan Das04f9f4c2023-09-13 23:59:05 +0000734 "api_surface": "api_surface",
Sam Delmerico5f906492023-03-15 18:06:18 -0400735 "stubs_symbol_file": "symbol_file",
736 "stubs_versions": "versions",
737 "soname": "soname",
738 "source_library_label": "source_library_label",
Trevor Radcliffe087af542022-09-16 15:36:10 +0000739 }
740
741 stubSuiteAttrs := AttrNameToString{}
742 for key, _ := range attrs {
743 if _, stubSuiteAttr := STUB_SUITE_ATTRS[key]; stubSuiteAttr {
744 stubSuiteAttrs[STUB_SUITE_ATTRS[key]] = attrs[key]
Sam Delmerico5f906492023-03-15 18:06:18 -0400745 } else {
746 panic(fmt.Sprintf("unused cc_stub_suite attr %q\n", key))
Trevor Radcliffe087af542022-09-16 15:36:10 +0000747 }
748 }
749 return MakeBazelTarget("cc_stub_suite", name+"_stub_libs", stubSuiteAttrs)
750}
Alix341484b2022-10-31 19:08:18 +0000751
752func MakeNeverlinkDuplicateTarget(moduleType string, name string) string {
Liz Kammer02914402023-08-07 13:38:18 -0400753 return MakeNeverlinkDuplicateTargetWithAttrs(moduleType, name, AttrNameToString{
754 "sdk_version": `"current"`, // use as default
755 })
Romain Jobredeaux2eef2e12023-02-24 12:07:08 -0500756}
757
758func MakeNeverlinkDuplicateTargetWithAttrs(moduleType string, name string, extraAttrs AttrNameToString) string {
759 attrs := extraAttrs
760 attrs["neverlink"] = `True`
761 attrs["exports"] = `[":` + name + `"]`
762 return MakeBazelTarget(moduleType, name+"-neverlink", attrs)
Alix341484b2022-10-31 19:08:18 +0000763}
Zi Wangfba0a212023-03-07 16:48:19 -0800764
765func getTargetName(targetContent string) string {
766 data := strings.Split(targetContent, "name = \"")
767 if len(data) < 2 {
768 return ""
769 } else {
770 endIndex := strings.Index(data[1], "\"")
771 return data[1][:endIndex]
772 }
773}