blob: eca6022793930649a2a48ef7fee76f9d69bd3737 [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
Spandan Das5af0bd32022-09-28 20:43:08 +000030 "github.com/google/blueprint/proptools"
31
Liz Kammer2dd9ca42020-11-25 16:06:39 -080032 "android/soong/android"
Sam Delmerico24c56032022-03-28 19:53:03 +000033 "android/soong/android/allowlists"
Jingwen Chen73850672020-12-14 08:25:34 -050034 "android/soong/bazel"
Liz Kammer2dd9ca42020-11-25 16:06:39 -080035)
36
Jingwen Chen91220d72021-03-24 02:18:33 -040037var (
Rupert Shuttleworth06559d02021-05-19 09:14:26 -040038 buildDir string
Jingwen Chen91220d72021-03-24 02:18:33 -040039)
40
Chris Parsonscd209032023-09-19 01:12:48 +000041var labelRegex = regexp.MustCompile(`^//([^: ]+):([^ ]+)$`)
42var simpleModuleNameRegex = regexp.MustCompile(`^[^: /]+$`)
43
Jingwen Chen5146ac02021-09-02 11:44:42 +000044func 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 +000045 t.Helper()
Jingwen Chen5146ac02021-09-02 11:44:42 +000046
Jingwen Chen5146ac02021-09-02 11:44:42 +000047 if len(errs) != 1 {
Liz Kammer6eff3232021-08-26 08:37:59 -040048 return false
Jingwen Chen5146ac02021-09-02 11:44:42 +000049 }
Liz Kammer54309532021-12-14 12:21:22 -050050 if strings.Contains(errs[0].Error(), expectedErr.Error()) {
Jingwen Chen5146ac02021-09-02 11:44:42 +000051 return true
52 }
53
54 return false
55}
56
Sam Delmerico3177a6e2022-06-21 19:28:33 +000057func errored(t *testing.T, tc Bp2buildTestCase, errs []error) bool {
Jingwen Chen5146ac02021-09-02 11:44:42 +000058 t.Helper()
Sam Delmerico3177a6e2022-06-21 19:28:33 +000059 if tc.ExpectedErr != nil {
Jingwen Chen5146ac02021-09-02 11:44:42 +000060 // Rely on checkErrors, as this test case is expected to have an error.
61 return false
62 }
63
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000064 if len(errs) > 0 {
65 for _, err := range errs {
Sam Delmerico3177a6e2022-06-21 19:28:33 +000066 t.Errorf("%s: %s", tc.Description, err)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000067 }
68 return true
69 }
Jingwen Chen5146ac02021-09-02 11:44:42 +000070
71 // All good, continue execution.
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000072 return false
73}
74
Trevor Radcliffe1b4b2d92022-09-01 18:57:01 +000075func RunBp2BuildTestCaseSimple(t *testing.T, tc Bp2buildTestCase) {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000076 t.Helper()
Sam Delmerico3177a6e2022-06-21 19:28:33 +000077 RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +000078}
79
Sam Delmerico3177a6e2022-06-21 19:28:33 +000080type Bp2buildTestCase struct {
81 Description string
82 ModuleTypeUnderTest string
83 ModuleTypeUnderTestFactory android.ModuleFactory
Sam Delmerico5840afc2023-06-12 15:44:03 -040084 // Text to add to the toplevel, root Android.bp file. If Dir is not set, all
85 // ExpectedBazelTargets are assumed to be generated by this file.
Chris Parsons39a16972023-06-08 14:28:51 +000086 Blueprint string
Sam Delmerico5840afc2023-06-12 15:44:03 -040087 // ExpectedBazelTargets compares the BazelTargets generated in `Dir` (if not empty).
88 // Otherwise, it checks the BazelTargets generated by `Blueprint` in the root directory.
89 ExpectedBazelTargets []string
Chris Parsons5011e612023-09-13 23:33:20 +000090 // AlreadyExistingBuildContents, if non-empty, simulates an already-present source BUILD file
91 // in the directory under test. The BUILD file has the given contents. This BUILD file
92 // will also be treated as "BUILD file to keep" by the simulated bp2build environment.
93 AlreadyExistingBuildContents string
Chris Parsonscd209032023-09-19 01:12:48 +000094
95 // StubbedBuildDefinitions, if non-empty, adds stub definitions to already-present source
96 // BUILD files for each bazel label given. The BUILD files with these stub definitions
97 // are added to the BUILD file given in AlreadyExistingBuildContents.
98 // Labels may be of the form //pkg/to:target_name (which would be defined in pkg/to/BUILD.bazel)
99 // or `target_name` (which would be defined in ./BUILD.bazel).
Chris Parsons5011e612023-09-13 23:33:20 +0000100 StubbedBuildDefinitions []string
101
102 Filesystem map[string]string
Sam Delmerico5840afc2023-06-12 15:44:03 -0400103 // Dir sets the directory which will be compared against the targets in ExpectedBazelTargets.
104 // This should used in conjunction with the Filesystem property to check for targets
105 // generated from a directory that is not the root.
106 // If not set, all ExpectedBazelTargets are assumed to be generated by the text in the
107 // Blueprint property.
108 Dir string
Trevor Radcliffe58ea4512022-04-07 20:36:39 +0000109 // An error with a string contained within the string of the expected error
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000110 ExpectedErr error
111 UnconvertedDepsMode unconvertedDepsMode
Jingwen Chen0eeaeb82022-09-21 10:27:42 +0000112
113 // For every directory listed here, the BUILD file for that directory will
114 // be merged with the generated BUILD file. This allows custom BUILD targets
115 // to be used in tests, or use BUILD files to draw package boundaries.
116 KeepBuildFileForDirs []string
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000117}
118
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000119func RunBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
Liz Kammerffc17e42022-11-23 09:42:05 -0500120 t.Helper()
Paul Duffin4c0765a2022-10-29 17:48:00 +0100121 bp2buildSetup := android.GroupFixturePreparers(
122 android.FixtureRegisterWithContext(registerModuleTypes),
123 SetBp2BuildTestRunner,
124 )
Spandan Das5af0bd32022-09-28 20:43:08 +0000125 runBp2BuildTestCaseWithSetup(t, bp2buildSetup, tc)
126}
127
Paul Duffin4c0765a2022-10-29 17:48:00 +0100128func 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 +0000129 t.Helper()
Chris Parsonscd209032023-09-19 01:12:48 +0000130 if tc.Filesystem == nil {
131 tc.Filesystem = map[string]string{}
132 }
Chris Parsons5011e612023-09-13 23:33:20 +0000133 checkDir := "."
134 if tc.Dir != "" {
135 checkDir = tc.Dir
136 }
137 keepExistingBuildDirs := tc.KeepBuildFileForDirs
138 buildFilesToParse := []string{}
Chris Parsonscd209032023-09-19 01:12:48 +0000139
140 if len(tc.StubbedBuildDefinitions) > 0 {
141 for _, buildDef := range tc.StubbedBuildDefinitions {
142 globalLabelMatch := labelRegex.FindStringSubmatch(buildDef)
143 var dir, targetName string
144 if len(globalLabelMatch) > 0 {
145 dir = globalLabelMatch[1]
146 targetName = globalLabelMatch[2]
147 } else {
148 if !simpleModuleNameRegex.MatchString(buildDef) {
149 t.Errorf("Stubbed build definition '%s' must be either a simple module name or of global target syntax (//foo/bar:baz).", buildDef)
150 return
151 }
152 dir = "."
153 targetName = buildDef
154 }
155 buildFilePath := filepath.Join(dir, "BUILD")
156 tc.Filesystem[buildFilePath] +=
157 MakeBazelTarget(
158 "bp2build_test_stub",
159 targetName,
160 AttrNameToString{})
161 keepExistingBuildDirs = append(keepExistingBuildDirs, dir)
162 buildFilesToParse = append(buildFilesToParse, buildFilePath)
163 }
164 }
165 if len(tc.AlreadyExistingBuildContents) > 0 {
166 buildFilePath := filepath.Join(checkDir, "BUILD")
167 tc.Filesystem[buildFilePath] += tc.AlreadyExistingBuildContents
168 keepExistingBuildDirs = append(keepExistingBuildDirs, checkDir)
169 buildFilesToParse = append(buildFilesToParse, buildFilePath)
170 }
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000171 filesystem := make(map[string][]byte)
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000172 for f, content := range tc.Filesystem {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000173 filesystem[f] = []byte(content)
174 }
Paul Duffin4c0765a2022-10-29 17:48:00 +0100175 preparers := []android.FixturePreparer{
176 extraPreparer,
177 android.FixtureMergeMockFs(filesystem),
178 android.FixtureWithRootAndroidBp(tc.Blueprint),
179 android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
180 ctx.RegisterModuleType(tc.ModuleTypeUnderTest, tc.ModuleTypeUnderTestFactory)
181 }),
Chris Parsons5011e612023-09-13 23:33:20 +0000182 android.FixtureModifyContextWithMockFs(func(ctx *android.TestContext) {
Paul Duffin4c0765a2022-10-29 17:48:00 +0100183 // A default configuration for tests to not have to specify bp2build_available on top level
184 // targets.
185 bp2buildConfig := android.NewBp2BuildAllowlist().SetDefaultConfig(
186 allowlists.Bp2BuildConfig{
187 android.Bp2BuildTopLevel: allowlists.Bp2BuildDefaultTrueRecursively,
188 },
189 )
Chris Parsons5011e612023-09-13 23:33:20 +0000190 for _, f := range keepExistingBuildDirs {
Paul Duffin4c0765a2022-10-29 17:48:00 +0100191 bp2buildConfig.SetKeepExistingBuildFile(map[string]bool{
192 f: /*recursive=*/ false,
193 })
194 }
195 ctx.RegisterBp2BuildConfig(bp2buildConfig)
Chris Parsons39a16972023-06-08 14:28:51 +0000196 // This setting is added to bp2build invocations. It prevents bp2build
197 // from cloning modules to their original state after mutators run. This
198 // would lose some data intentionally set by these mutators.
199 ctx.SkipCloneModulesAfterMutators = true
Chris Parsons5011e612023-09-13 23:33:20 +0000200 err := ctx.RegisterExistingBazelTargets(".", buildFilesToParse)
201 if err != nil {
202 t.Errorf("error parsing build files in test setup: %s", err)
203 }
Paul Duffin4c0765a2022-10-29 17:48:00 +0100204 }),
205 android.FixtureModifyEnv(func(env map[string]string) {
206 if tc.UnconvertedDepsMode == errorModulesUnconvertedDeps {
207 env["BP2BUILD_ERROR_UNCONVERTED"] = "true"
208 }
209 }),
Jingwen Chen5146ac02021-09-02 11:44:42 +0000210 }
211
Paul Duffin4c0765a2022-10-29 17:48:00 +0100212 preparer := android.GroupFixturePreparers(preparers...)
213 if tc.ExpectedErr != nil {
214 pattern := "\\Q" + tc.ExpectedErr.Error() + "\\E"
215 preparer = preparer.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(pattern))
216 }
217 result := preparer.RunTestWithCustomResult(t).(*BazelTestResult)
218 if len(result.Errs) > 0 {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000219 return
220 }
221
Paul Duffin4c0765a2022-10-29 17:48:00 +0100222 expectedTargets := map[string][]string{
223 checkDir: tc.ExpectedBazelTargets,
Liz Kammer6eff3232021-08-26 08:37:59 -0400224 }
Paul Duffin4c0765a2022-10-29 17:48:00 +0100225
226 result.CompareAllBazelTargets(t, tc.Description, expectedTargets, true)
227}
228
229// SetBp2BuildTestRunner customizes the test fixture mechanism to run tests in Bp2Build mode.
Chris Parsons73f411b2023-06-20 21:46:57 +0000230var SetBp2BuildTestRunner = android.FixtureSetTestRunner(&bazelTestRunner{})
Paul Duffin4c0765a2022-10-29 17:48:00 +0100231
Chris Parsons73f411b2023-06-20 21:46:57 +0000232// bazelTestRunner customizes the test fixture mechanism to run tests of the bp2build build mode.
233type bazelTestRunner struct{}
Paul Duffin4c0765a2022-10-29 17:48:00 +0100234
235func (b *bazelTestRunner) FinalPreparer(result *android.TestResult) android.CustomTestResult {
236 ctx := result.TestContext
Chris Parsons73f411b2023-06-20 21:46:57 +0000237 ctx.RegisterForBazelConversion()
Paul Duffin4c0765a2022-10-29 17:48:00 +0100238
239 return &BazelTestResult{TestResult: result}
240}
241
242func (b *bazelTestRunner) PostParseProcessor(result android.CustomTestResult) {
243 bazelResult := result.(*BazelTestResult)
244 ctx := bazelResult.TestContext
245 config := bazelResult.Config
246 _, errs := ctx.ResolveDependencies(config)
247 if bazelResult.CollateErrs(errs) {
248 return
249 }
250
Chris Parsons73f411b2023-06-20 21:46:57 +0000251 codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "")
Paul Duffin4c0765a2022-10-29 17:48:00 +0100252 res, errs := GenerateBazelTargets(codegenCtx, false)
253 if bazelResult.CollateErrs(errs) {
254 return
255 }
256
257 // Store additional data for access by tests.
258 bazelResult.conversionResults = res
259}
260
261// BazelTestResult is a wrapper around android.TestResult to provide type safe access to the bazel
262// specific data stored by the bazelTestRunner.
263type BazelTestResult struct {
264 *android.TestResult
265
266 // The result returned by the GenerateBazelTargets function.
267 conversionResults
268}
269
270// CompareAllBazelTargets compares the BazelTargets produced by the test for all the directories
271// with the supplied set of expected targets.
272//
273// If ignoreUnexpected=false then this enforces an exact match where every BazelTarget produced must
274// have a corresponding expected BazelTarget.
275//
276// If ignoreUnexpected=true then it will ignore directories for which there are no expected targets.
277func (b BazelTestResult) CompareAllBazelTargets(t *testing.T, description string, expectedTargets map[string][]string, ignoreUnexpected bool) {
Liz Kammer2b3f56e2023-03-23 11:51:49 -0400278 t.Helper()
Paul Duffin4c0765a2022-10-29 17:48:00 +0100279 actualTargets := b.buildFileToTargets
280
281 // Generate the sorted set of directories to check.
Cole Faust18994c72023-02-28 16:02:16 -0800282 dirsToCheck := android.SortedKeys(expectedTargets)
Paul Duffin4c0765a2022-10-29 17:48:00 +0100283 if !ignoreUnexpected {
284 // This needs to perform an exact match so add the directories in which targets were
285 // produced to the list of directories to check.
Cole Faust18994c72023-02-28 16:02:16 -0800286 dirsToCheck = append(dirsToCheck, android.SortedKeys(actualTargets)...)
Paul Duffin4c0765a2022-10-29 17:48:00 +0100287 dirsToCheck = android.SortedUniqueStrings(dirsToCheck)
288 }
289
290 for _, dir := range dirsToCheck {
291 expected := expectedTargets[dir]
292 actual := actualTargets[dir]
293
294 if expected == nil {
295 if actual != nil {
296 t.Errorf("did not expect any bazel modules in %q but found %d", dir, len(actual))
297 }
298 } else if actual == nil {
299 expectedCount := len(expected)
300 if expectedCount > 0 {
301 t.Errorf("expected %d bazel modules in %q but did not find any", expectedCount, dir)
302 }
303 } else {
304 b.CompareBazelTargets(t, description, expected, actual)
305 }
306 }
307}
308
309func (b BazelTestResult) CompareBazelTargets(t *testing.T, description string, expectedContents []string, actualTargets BazelTargets) {
Liz Kammer748d7072023-01-25 12:07:43 -0500310 t.Helper()
Paul Duffin4c0765a2022-10-29 17:48:00 +0100311 if actualCount, expectedCount := len(actualTargets), len(expectedContents); actualCount != expectedCount {
Sasha Smundak9d2f1742022-08-04 13:28:38 -0700312 t.Errorf("%s: Expected %d bazel target (%s), got %d (%s)",
Paul Duffin4c0765a2022-10-29 17:48:00 +0100313 description, expectedCount, expectedContents, actualCount, actualTargets)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000314 } else {
Zi Wangfba0a212023-03-07 16:48:19 -0800315 sort.SliceStable(actualTargets, func(i, j int) bool {
316 return actualTargets[i].name < actualTargets[j].name
317 })
318 sort.SliceStable(expectedContents, func(i, j int) bool {
319 return getTargetName(expectedContents[i]) < getTargetName(expectedContents[j])
320 })
Paul Duffin4c0765a2022-10-29 17:48:00 +0100321 for i, actualTarget := range actualTargets {
322 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 +0000323 t.Errorf(
Paul Duffin4c0765a2022-10-29 17:48:00 +0100324 "%s[%d]: Expected generated Bazel target to be `%s`, got `%s`",
325 description, i, w, g)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux1c92aef2021-08-23 16:10:00 +0000326 }
327 }
328 }
329}
330
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800331type nestedProps struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500332 Nested_prop *string
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800333}
334
Liz Kammer32a03392021-09-14 11:17:21 -0400335type EmbeddedProps struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500336 Embedded_prop *string
Liz Kammer32a03392021-09-14 11:17:21 -0400337}
338
339type OtherEmbeddedProps struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500340 Other_embedded_prop *string
Liz Kammer32a03392021-09-14 11:17:21 -0400341}
342
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800343type customProps struct {
Liz Kammer32a03392021-09-14 11:17:21 -0400344 EmbeddedProps
345 *OtherEmbeddedProps
346
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800347 Bool_prop bool
348 Bool_ptr_prop *bool
349 // 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 +0000350 Int_prop int `blueprint:"mutated"`
351 Int64_ptr_prop *int64
352 String_prop string
353 String_literal_prop *string `android:"arch_variant"`
354 String_ptr_prop *string
355 String_list_prop []string
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800356
357 Nested_props nestedProps
358 Nested_props_ptr *nestedProps
Liz Kammer4562a3b2021-04-21 18:15:34 -0400359
Liz Kammer32b77cf2021-08-04 15:17:02 -0400360 Arch_paths []string `android:"path,arch_variant"`
361 Arch_paths_exclude []string `android:"path,arch_variant"`
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400362
363 // Prop used to indicate this conversion should be 1 module -> multiple targets
364 One_to_many_prop *bool
Spandan Das5af0bd32022-09-28 20:43:08 +0000365
366 Api *string // File describing the APIs of this module
Spandan Das6a448ec2023-04-19 17:36:12 +0000367
368 Test_config_setting *bool // Used to test generation of config_setting targets
Spandan Das3131d672023-08-03 22:33:47 +0000369
370 Dir *string // Dir in which the Bazel Target will be created
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800371}
372
373type customModule struct {
374 android.ModuleBase
Liz Kammerea6666f2021-02-17 10:17:28 -0500375 android.BazelModuleBase
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800376
377 props customProps
378}
379
380// OutputFiles is needed because some instances of this module use dist with a
381// tag property which requires the module implements OutputFileProducer.
382func (m *customModule) OutputFiles(tag string) (android.Paths, error) {
383 return android.PathsForTesting("path" + tag), nil
384}
385
386func (m *customModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
387 // nothing for now.
388}
389
390func customModuleFactoryBase() android.Module {
391 module := &customModule{}
392 module.AddProperties(&module.props)
Liz Kammerea6666f2021-02-17 10:17:28 -0500393 android.InitBazelModule(module)
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800394 return module
395}
396
Liz Kammerdfeb1202022-05-13 17:20:20 -0400397func customModuleFactoryHostAndDevice() android.Module {
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800398 m := customModuleFactoryBase()
Liz Kammer4562a3b2021-04-21 18:15:34 -0400399 android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibBoth)
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800400 return m
401}
402
Liz Kammerdfeb1202022-05-13 17:20:20 -0400403func customModuleFactoryDeviceSupported() android.Module {
404 m := customModuleFactoryBase()
405 android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibBoth)
406 return m
407}
408
409func customModuleFactoryHostSupported() android.Module {
410 m := customModuleFactoryBase()
411 android.InitAndroidArchModule(m, android.HostSupported, android.MultilibBoth)
412 return m
413}
414
415func customModuleFactoryHostAndDeviceDefault() android.Module {
416 m := customModuleFactoryBase()
417 android.InitAndroidArchModule(m, android.HostAndDeviceDefault, android.MultilibBoth)
418 return m
419}
420
421func customModuleFactoryNeitherHostNorDeviceSupported() android.Module {
422 m := customModuleFactoryBase()
423 android.InitAndroidArchModule(m, android.NeitherHostNorDeviceSupported, android.MultilibBoth)
424 return m
425}
426
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800427type testProps struct {
428 Test_prop struct {
429 Test_string_prop string
430 }
431}
432
433type customTestModule struct {
434 android.ModuleBase
435
436 props customProps
437 test_props testProps
438}
439
440func (m *customTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
441 // nothing for now.
442}
443
444func customTestModuleFactoryBase() android.Module {
445 m := &customTestModule{}
446 m.AddProperties(&m.props)
447 m.AddProperties(&m.test_props)
448 return m
449}
450
451func customTestModuleFactory() android.Module {
452 m := customTestModuleFactoryBase()
453 android.InitAndroidModule(m)
454 return m
455}
456
457type customDefaultsModule struct {
458 android.ModuleBase
459 android.DefaultsModuleBase
460}
461
462func customDefaultsModuleFactoryBase() android.DefaultsModule {
463 module := &customDefaultsModule{}
464 module.AddProperties(&customProps{})
465 return module
466}
467
468func customDefaultsModuleFactoryBasic() android.Module {
469 return customDefaultsModuleFactoryBase()
470}
471
472func customDefaultsModuleFactory() android.Module {
473 m := customDefaultsModuleFactoryBase()
474 android.InitDefaultsModule(m)
475 return m
476}
Jingwen Chen73850672020-12-14 08:25:34 -0500477
Liz Kammer32a03392021-09-14 11:17:21 -0400478type EmbeddedAttr struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500479 Embedded_attr *string
Liz Kammer32a03392021-09-14 11:17:21 -0400480}
481
482type OtherEmbeddedAttr struct {
Liz Kammer46fb7ab2021-12-01 10:09:34 -0500483 Other_embedded_attr *string
Liz Kammer32a03392021-09-14 11:17:21 -0400484}
485
Jingwen Chen73850672020-12-14 08:25:34 -0500486type customBazelModuleAttributes struct {
Liz Kammer32a03392021-09-14 11:17:21 -0400487 EmbeddedAttr
488 *OtherEmbeddedAttr
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000489 String_literal_prop bazel.StringAttribute
490 String_ptr_prop *string
491 String_list_prop []string
492 Arch_paths bazel.LabelListAttribute
Spandan Das5af0bd32022-09-28 20:43:08 +0000493 Api bazel.LabelAttribute
Jingwen Chen73850672020-12-14 08:25:34 -0500494}
495
Spandan Das3131d672023-08-03 22:33:47 +0000496func (m *customModule) dir() *string {
497 return m.props.Dir
498}
499
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400500func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400501 if p := m.props.One_to_many_prop; p != nil && *p {
502 customBp2buildOneToMany(ctx, m)
503 return
504 }
Liz Kammer4562a3b2021-04-21 18:15:34 -0400505
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000506 paths := bazel.LabelListAttribute{}
507 strAttr := bazel.StringAttribute{}
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400508 for axis, configToProps := range m.GetArchVariantProperties(ctx, &customProps{}) {
509 for config, props := range configToProps {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000510 if custProps, ok := props.(*customProps); ok {
511 if custProps.Arch_paths != nil {
512 paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrcExcludes(ctx, custProps.Arch_paths, custProps.Arch_paths_exclude))
513 }
514 if custProps.String_literal_prop != nil {
515 strAttr.SetSelectValue(axis, config, custProps.String_literal_prop)
516 }
Liz Kammer4562a3b2021-04-21 18:15:34 -0400517 }
518 }
Jingwen Chen73850672020-12-14 08:25:34 -0500519 }
Liz Kammer9e2a5a72023-09-19 08:41:14 -0400520 productVariableProps, errs := android.ProductVariableProperties(ctx, ctx.Module())
521 for _, err := range errs {
522 ctx.ModuleErrorf("ProductVariableProperties error: %s", err)
523 }
Liz Kammer9d2d4102022-12-21 14:51:37 -0500524 if props, ok := productVariableProps["String_literal_prop"]; ok {
525 for c, p := range props {
526 if val, ok := p.(*string); ok {
527 strAttr.SetSelectValue(c.ConfigurationAxis(), c.SelectKey(), val)
528 }
529 }
530 }
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400531
532 paths.ResolveExcludes()
533
534 attrs := &customBazelModuleAttributes{
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000535 String_literal_prop: strAttr,
536 String_ptr_prop: m.props.String_ptr_prop,
537 String_list_prop: m.props.String_list_prop,
538 Arch_paths: paths,
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400539 }
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000540
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400541 attrs.Embedded_attr = m.props.Embedded_prop
542 if m.props.OtherEmbeddedProps != nil {
543 attrs.OtherEmbeddedAttr = &OtherEmbeddedAttr{Other_embedded_attr: m.props.OtherEmbeddedProps.Other_embedded_prop}
544 }
545
546 props := bazel.BazelTargetModuleProperties{
547 Rule_class: "custom",
548 }
549
Spandan Das3131d672023-08-03 22:33:47 +0000550 ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name(), Dir: m.dir()}, attrs)
Spandan Das6a448ec2023-04-19 17:36:12 +0000551
552 if proptools.Bool(m.props.Test_config_setting) {
553 m.createConfigSetting(ctx)
554 }
555
556}
557
558func (m *customModule) createConfigSetting(ctx android.TopDownMutatorContext) {
559 csa := bazel.ConfigSettingAttributes{
560 Flag_values: bazel.StringMapAttribute{
561 "//build/bazel/rules/my_string_setting": m.Name(),
562 },
563 }
564 ca := android.CommonAttributes{
565 Name: m.Name() + "_config_setting",
566 }
567 ctx.CreateBazelConfigSetting(
568 csa,
569 ca,
570 ctx.ModuleDir(),
571 )
Jingwen Chen73850672020-12-14 08:25:34 -0500572}
Jingwen Chen40067de2021-01-26 21:58:43 -0500573
Spandan Das5af0bd32022-09-28 20:43:08 +0000574var _ android.ApiProvider = (*customModule)(nil)
575
576func (c *customModule) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
577 props := bazel.BazelTargetModuleProperties{
578 Rule_class: "custom_api_contribution",
579 }
580 apiAttribute := bazel.MakeLabelAttribute(
581 android.BazelLabelForModuleSrcSingle(ctx, proptools.String(c.props.Api)).Label,
582 )
583 attrs := &customBazelModuleAttributes{
584 Api: *apiAttribute,
585 }
586 ctx.CreateBazelTargetModule(props,
587 android.CommonAttributes{Name: c.Name()},
588 attrs)
589}
590
Jingwen Chen40067de2021-01-26 21:58:43 -0500591// A bp2build mutator that uses load statements and creates a 1:M mapping from
592// module to target.
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400593func customBp2buildOneToMany(ctx android.TopDownMutatorContext, m *customModule) {
Jingwen Chen77e8b7b2021-02-05 03:03:24 -0500594
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400595 baseName := m.Name()
596 attrs := &customBazelModuleAttributes{}
Jingwen Chen1fd14692021-02-05 03:01:50 -0500597
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400598 myLibraryProps := bazel.BazelTargetModuleProperties{
599 Rule_class: "my_library",
600 Bzl_load_location: "//build/bazel/rules:rules.bzl",
Jingwen Chen40067de2021-01-26 21:58:43 -0500601 }
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400602 ctx.CreateBazelTargetModule(myLibraryProps, android.CommonAttributes{Name: baseName}, attrs)
603
604 protoLibraryProps := bazel.BazelTargetModuleProperties{
605 Rule_class: "proto_library",
606 Bzl_load_location: "//build/bazel/rules:proto.bzl",
607 }
608 ctx.CreateBazelTargetModule(protoLibraryProps, android.CommonAttributes{Name: baseName + "_proto_library_deps"}, attrs)
609
610 myProtoLibraryProps := bazel.BazelTargetModuleProperties{
611 Rule_class: "my_proto_library",
612 Bzl_load_location: "//build/bazel/rules:proto.bzl",
613 }
614 ctx.CreateBazelTargetModule(myProtoLibraryProps, android.CommonAttributes{Name: baseName + "_my_proto_library_deps"}, attrs)
Jingwen Chen40067de2021-01-26 21:58:43 -0500615}
Jingwen Chenba369ad2021-02-22 10:19:34 -0500616
617// Helper method for tests to easily access the targets in a dir.
Liz Kammer6eff3232021-08-26 08:37:59 -0400618func generateBazelTargetsForDir(codegenCtx *CodegenContext, dir string) (BazelTargets, []error) {
Rupert Shuttleworth2a4fc3e2021-04-21 07:10:09 -0400619 // TODO: Set generateFilegroups to true and/or remove the generateFilegroups argument completely
Liz Kammer6eff3232021-08-26 08:37:59 -0400620 res, err := GenerateBazelTargets(codegenCtx, false)
Alix94e26032022-08-16 20:37:33 +0000621 if err != nil {
622 return BazelTargets{}, err
623 }
Liz Kammer6eff3232021-08-26 08:37:59 -0400624 return res.buildFileToTargets[dir], err
Jingwen Chenba369ad2021-02-22 10:19:34 -0500625}
Liz Kammer32b77cf2021-08-04 15:17:02 -0400626
627func registerCustomModuleForBp2buildConversion(ctx *android.TestContext) {
Liz Kammerdfeb1202022-05-13 17:20:20 -0400628 ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
Liz Kammer32b77cf2021-08-04 15:17:02 -0400629 ctx.RegisterForBazelConversion()
630}
Liz Kammer7a210ac2021-09-22 15:52:58 -0400631
Chris Parsonscd209032023-09-19 01:12:48 +0000632func simpleModule(typ, name string) string {
Liz Kammer7a210ac2021-09-22 15:52:58 -0400633 return fmt.Sprintf(`
634%s {
635 name: "%s",
Liz Kammer7a210ac2021-09-22 15:52:58 -0400636}`, typ, name)
637}
Liz Kammer78cfdaa2021-11-08 12:56:31 -0500638
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000639type AttrNameToString map[string]string
Liz Kammer78cfdaa2021-11-08 12:56:31 -0500640
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000641func (a AttrNameToString) clone() AttrNameToString {
642 newAttrs := make(AttrNameToString, len(a))
Liz Kammerdfeb1202022-05-13 17:20:20 -0400643 for k, v := range a {
644 newAttrs[k] = v
645 }
646 return newAttrs
647}
648
649// makeBazelTargetNoRestrictions returns bazel target build file definition that can be host or
650// device specific, or independent of host/device.
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000651func makeBazelTargetHostOrDevice(typ, name string, attrs AttrNameToString, hod android.HostOrDeviceSupported) string {
Liz Kammerdfeb1202022-05-13 17:20:20 -0400652 if _, ok := attrs["target_compatible_with"]; !ok {
653 switch hod {
654 case android.HostSupported:
655 attrs["target_compatible_with"] = `select({
656 "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
657 "//conditions:default": [],
658 })`
659 case android.DeviceSupported:
660 attrs["target_compatible_with"] = `["//build/bazel/platforms/os:android"]`
661 }
662 }
663
Liz Kammer78cfdaa2021-11-08 12:56:31 -0500664 attrStrings := make([]string, 0, len(attrs)+1)
Sasha Smundakfb589492022-08-04 11:13:27 -0700665 if name != "" {
666 attrStrings = append(attrStrings, fmt.Sprintf(` name = "%s",`, name))
667 }
Cole Faust18994c72023-02-28 16:02:16 -0800668 for _, k := range android.SortedKeys(attrs) {
Liz Kammer78cfdaa2021-11-08 12:56:31 -0500669 attrStrings = append(attrStrings, fmt.Sprintf(" %s = %s,", k, attrs[k]))
670 }
671 return fmt.Sprintf(`%s(
672%s
673)`, typ, strings.Join(attrStrings, "\n"))
674}
Liz Kammerdfeb1202022-05-13 17:20:20 -0400675
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000676// MakeBazelTargetNoRestrictions returns bazel target build file definition that does not add a
Liz Kammerdfeb1202022-05-13 17:20:20 -0400677// target_compatible_with. This is useful for module types like filegroup and genrule that arch not
678// arch variant
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000679func MakeBazelTargetNoRestrictions(typ, name string, attrs AttrNameToString) string {
Liz Kammerdfeb1202022-05-13 17:20:20 -0400680 return makeBazelTargetHostOrDevice(typ, name, attrs, android.HostAndDeviceDefault)
681}
682
683// makeBazelTargetNoRestrictions returns bazel target build file definition that is device specific
684// as this is the most common default in Soong.
Alixe06d75b2022-08-31 18:28:19 +0000685func MakeBazelTarget(typ, name string, attrs AttrNameToString) string {
Liz Kammerdfeb1202022-05-13 17:20:20 -0400686 return makeBazelTargetHostOrDevice(typ, name, attrs, android.DeviceSupported)
687}
Sasha Smundak9d2f1742022-08-04 13:28:38 -0700688
689type ExpectedRuleTarget struct {
690 Rule string
691 Name string
692 Attrs AttrNameToString
693 Hod android.HostOrDeviceSupported
694}
695
696func (ebr ExpectedRuleTarget) String() string {
697 return makeBazelTargetHostOrDevice(ebr.Rule, ebr.Name, ebr.Attrs, ebr.Hod)
698}
Trevor Radcliffe087af542022-09-16 15:36:10 +0000699
700func makeCcStubSuiteTargets(name string, attrs AttrNameToString) string {
701 if _, hasStubs := attrs["stubs_symbol_file"]; !hasStubs {
702 return ""
703 }
704 STUB_SUITE_ATTRS := map[string]string{
Spandan Das04f9f4c2023-09-13 23:59:05 +0000705 "api_surface": "api_surface",
Sam Delmerico5f906492023-03-15 18:06:18 -0400706 "stubs_symbol_file": "symbol_file",
707 "stubs_versions": "versions",
708 "soname": "soname",
709 "source_library_label": "source_library_label",
Trevor Radcliffe087af542022-09-16 15:36:10 +0000710 }
711
712 stubSuiteAttrs := AttrNameToString{}
713 for key, _ := range attrs {
714 if _, stubSuiteAttr := STUB_SUITE_ATTRS[key]; stubSuiteAttr {
715 stubSuiteAttrs[STUB_SUITE_ATTRS[key]] = attrs[key]
Sam Delmerico5f906492023-03-15 18:06:18 -0400716 } else {
717 panic(fmt.Sprintf("unused cc_stub_suite attr %q\n", key))
Trevor Radcliffe087af542022-09-16 15:36:10 +0000718 }
719 }
720 return MakeBazelTarget("cc_stub_suite", name+"_stub_libs", stubSuiteAttrs)
721}
Alix341484b2022-10-31 19:08:18 +0000722
723func MakeNeverlinkDuplicateTarget(moduleType string, name string) string {
Liz Kammer02914402023-08-07 13:38:18 -0400724 return MakeNeverlinkDuplicateTargetWithAttrs(moduleType, name, AttrNameToString{
725 "sdk_version": `"current"`, // use as default
726 })
Romain Jobredeaux2eef2e12023-02-24 12:07:08 -0500727}
728
729func MakeNeverlinkDuplicateTargetWithAttrs(moduleType string, name string, extraAttrs AttrNameToString) string {
730 attrs := extraAttrs
731 attrs["neverlink"] = `True`
732 attrs["exports"] = `[":` + name + `"]`
733 return MakeBazelTarget(moduleType, name+"-neverlink", attrs)
Alix341484b2022-10-31 19:08:18 +0000734}
Zi Wangfba0a212023-03-07 16:48:19 -0800735
736func getTargetName(targetContent string) string {
737 data := strings.Split(targetContent, "name = \"")
738 if len(data) < 2 {
739 return ""
740 } else {
741 endIndex := strings.Index(data[1], "\"")
742 return data[1][:endIndex]
743 }
744}