6a448ec1a3
The use case for this is creating config_setting(s) specific to an apex variant and selecting stub/impl in that config_setting. We likely need only a handful of such config_setting(s), but determining that list requires iterating the build graph. Test: go test ./bp2build Change-Id: I9aa552e3d0bcf67513023c3a7d4bbf8fae464ee4
686 lines
20 KiB
Go
686 lines
20 KiB
Go
// Copyright 2021 Google Inc. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package bp2build
|
|
|
|
/*
|
|
For shareable/common bp2build testing functionality and dumping ground for
|
|
specific-but-shared functionality among tests in package
|
|
*/
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/google/blueprint/proptools"
|
|
|
|
"android/soong/android"
|
|
"android/soong/android/allowlists"
|
|
"android/soong/bazel"
|
|
)
|
|
|
|
var (
|
|
buildDir string
|
|
)
|
|
|
|
func checkError(t *testing.T, errs []error, expectedErr error) bool {
|
|
t.Helper()
|
|
|
|
if len(errs) != 1 {
|
|
return false
|
|
}
|
|
if strings.Contains(errs[0].Error(), expectedErr.Error()) {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func errored(t *testing.T, tc Bp2buildTestCase, errs []error) bool {
|
|
t.Helper()
|
|
if tc.ExpectedErr != nil {
|
|
// Rely on checkErrors, as this test case is expected to have an error.
|
|
return false
|
|
}
|
|
|
|
if len(errs) > 0 {
|
|
for _, err := range errs {
|
|
t.Errorf("%s: %s", tc.Description, err)
|
|
}
|
|
return true
|
|
}
|
|
|
|
// All good, continue execution.
|
|
return false
|
|
}
|
|
|
|
func RunBp2BuildTestCaseSimple(t *testing.T, tc Bp2buildTestCase) {
|
|
t.Helper()
|
|
RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
|
|
}
|
|
|
|
type Bp2buildTestCase struct {
|
|
Description string
|
|
ModuleTypeUnderTest string
|
|
ModuleTypeUnderTestFactory android.ModuleFactory
|
|
Blueprint string
|
|
ExpectedBazelTargets []string
|
|
Filesystem map[string]string
|
|
Dir string
|
|
// An error with a string contained within the string of the expected error
|
|
ExpectedErr error
|
|
UnconvertedDepsMode unconvertedDepsMode
|
|
|
|
// For every directory listed here, the BUILD file for that directory will
|
|
// be merged with the generated BUILD file. This allows custom BUILD targets
|
|
// to be used in tests, or use BUILD files to draw package boundaries.
|
|
KeepBuildFileForDirs []string
|
|
}
|
|
|
|
func RunBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
|
|
t.Helper()
|
|
bp2buildSetup := android.GroupFixturePreparers(
|
|
android.FixtureRegisterWithContext(registerModuleTypes),
|
|
SetBp2BuildTestRunner,
|
|
)
|
|
runBp2BuildTestCaseWithSetup(t, bp2buildSetup, tc)
|
|
}
|
|
|
|
func RunApiBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
|
|
t.Helper()
|
|
apiBp2BuildSetup := android.GroupFixturePreparers(
|
|
android.FixtureRegisterWithContext(registerModuleTypes),
|
|
SetApiBp2BuildTestRunner,
|
|
)
|
|
runBp2BuildTestCaseWithSetup(t, apiBp2BuildSetup, tc)
|
|
}
|
|
|
|
func runBp2BuildTestCaseWithSetup(t *testing.T, extraPreparer android.FixturePreparer, tc Bp2buildTestCase) {
|
|
t.Helper()
|
|
dir := "."
|
|
filesystem := make(map[string][]byte)
|
|
for f, content := range tc.Filesystem {
|
|
filesystem[f] = []byte(content)
|
|
}
|
|
|
|
preparers := []android.FixturePreparer{
|
|
extraPreparer,
|
|
android.FixtureMergeMockFs(filesystem),
|
|
android.FixtureWithRootAndroidBp(tc.Blueprint),
|
|
android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
|
|
ctx.RegisterModuleType(tc.ModuleTypeUnderTest, tc.ModuleTypeUnderTestFactory)
|
|
}),
|
|
android.FixtureModifyContext(func(ctx *android.TestContext) {
|
|
// A default configuration for tests to not have to specify bp2build_available on top level
|
|
// targets.
|
|
bp2buildConfig := android.NewBp2BuildAllowlist().SetDefaultConfig(
|
|
allowlists.Bp2BuildConfig{
|
|
android.Bp2BuildTopLevel: allowlists.Bp2BuildDefaultTrueRecursively,
|
|
},
|
|
)
|
|
for _, f := range tc.KeepBuildFileForDirs {
|
|
bp2buildConfig.SetKeepExistingBuildFile(map[string]bool{
|
|
f: /*recursive=*/ false,
|
|
})
|
|
}
|
|
ctx.RegisterBp2BuildConfig(bp2buildConfig)
|
|
}),
|
|
android.FixtureModifyEnv(func(env map[string]string) {
|
|
if tc.UnconvertedDepsMode == errorModulesUnconvertedDeps {
|
|
env["BP2BUILD_ERROR_UNCONVERTED"] = "true"
|
|
}
|
|
}),
|
|
}
|
|
|
|
preparer := android.GroupFixturePreparers(preparers...)
|
|
if tc.ExpectedErr != nil {
|
|
pattern := "\\Q" + tc.ExpectedErr.Error() + "\\E"
|
|
preparer = preparer.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(pattern))
|
|
}
|
|
result := preparer.RunTestWithCustomResult(t).(*BazelTestResult)
|
|
if len(result.Errs) > 0 {
|
|
return
|
|
}
|
|
|
|
checkDir := dir
|
|
if tc.Dir != "" {
|
|
checkDir = tc.Dir
|
|
}
|
|
expectedTargets := map[string][]string{
|
|
checkDir: tc.ExpectedBazelTargets,
|
|
}
|
|
|
|
result.CompareAllBazelTargets(t, tc.Description, expectedTargets, true)
|
|
}
|
|
|
|
// SetBp2BuildTestRunner customizes the test fixture mechanism to run tests in Bp2Build mode.
|
|
var SetBp2BuildTestRunner = android.FixtureSetTestRunner(&bazelTestRunner{Bp2Build})
|
|
|
|
// SetApiBp2BuildTestRunner customizes the test fixture mechanism to run tests in ApiBp2build mode.
|
|
var SetApiBp2BuildTestRunner = android.FixtureSetTestRunner(&bazelTestRunner{ApiBp2build})
|
|
|
|
// bazelTestRunner customizes the test fixture mechanism to run tests of the bp2build and
|
|
// apiBp2build build modes.
|
|
type bazelTestRunner struct {
|
|
mode CodegenMode
|
|
}
|
|
|
|
func (b *bazelTestRunner) FinalPreparer(result *android.TestResult) android.CustomTestResult {
|
|
ctx := result.TestContext
|
|
switch b.mode {
|
|
case Bp2Build:
|
|
ctx.RegisterForBazelConversion()
|
|
case ApiBp2build:
|
|
ctx.RegisterForApiBazelConversion()
|
|
default:
|
|
panic(fmt.Errorf("unknown build mode: %d", b.mode))
|
|
}
|
|
|
|
return &BazelTestResult{TestResult: result}
|
|
}
|
|
|
|
func (b *bazelTestRunner) PostParseProcessor(result android.CustomTestResult) {
|
|
bazelResult := result.(*BazelTestResult)
|
|
ctx := bazelResult.TestContext
|
|
config := bazelResult.Config
|
|
_, errs := ctx.ResolveDependencies(config)
|
|
if bazelResult.CollateErrs(errs) {
|
|
return
|
|
}
|
|
|
|
codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "")
|
|
res, errs := GenerateBazelTargets(codegenCtx, false)
|
|
if bazelResult.CollateErrs(errs) {
|
|
return
|
|
}
|
|
|
|
// Store additional data for access by tests.
|
|
bazelResult.conversionResults = res
|
|
}
|
|
|
|
// BazelTestResult is a wrapper around android.TestResult to provide type safe access to the bazel
|
|
// specific data stored by the bazelTestRunner.
|
|
type BazelTestResult struct {
|
|
*android.TestResult
|
|
|
|
// The result returned by the GenerateBazelTargets function.
|
|
conversionResults
|
|
}
|
|
|
|
// CompareAllBazelTargets compares the BazelTargets produced by the test for all the directories
|
|
// with the supplied set of expected targets.
|
|
//
|
|
// If ignoreUnexpected=false then this enforces an exact match where every BazelTarget produced must
|
|
// have a corresponding expected BazelTarget.
|
|
//
|
|
// If ignoreUnexpected=true then it will ignore directories for which there are no expected targets.
|
|
func (b BazelTestResult) CompareAllBazelTargets(t *testing.T, description string, expectedTargets map[string][]string, ignoreUnexpected bool) {
|
|
t.Helper()
|
|
actualTargets := b.buildFileToTargets
|
|
|
|
// Generate the sorted set of directories to check.
|
|
dirsToCheck := android.SortedKeys(expectedTargets)
|
|
if !ignoreUnexpected {
|
|
// This needs to perform an exact match so add the directories in which targets were
|
|
// produced to the list of directories to check.
|
|
dirsToCheck = append(dirsToCheck, android.SortedKeys(actualTargets)...)
|
|
dirsToCheck = android.SortedUniqueStrings(dirsToCheck)
|
|
}
|
|
|
|
for _, dir := range dirsToCheck {
|
|
expected := expectedTargets[dir]
|
|
actual := actualTargets[dir]
|
|
|
|
if expected == nil {
|
|
if actual != nil {
|
|
t.Errorf("did not expect any bazel modules in %q but found %d", dir, len(actual))
|
|
}
|
|
} else if actual == nil {
|
|
expectedCount := len(expected)
|
|
if expectedCount > 0 {
|
|
t.Errorf("expected %d bazel modules in %q but did not find any", expectedCount, dir)
|
|
}
|
|
} else {
|
|
b.CompareBazelTargets(t, description, expected, actual)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (b BazelTestResult) CompareBazelTargets(t *testing.T, description string, expectedContents []string, actualTargets BazelTargets) {
|
|
t.Helper()
|
|
if actualCount, expectedCount := len(actualTargets), len(expectedContents); actualCount != expectedCount {
|
|
t.Errorf("%s: Expected %d bazel target (%s), got %d (%s)",
|
|
description, expectedCount, expectedContents, actualCount, actualTargets)
|
|
} else {
|
|
sort.SliceStable(actualTargets, func(i, j int) bool {
|
|
return actualTargets[i].name < actualTargets[j].name
|
|
})
|
|
sort.SliceStable(expectedContents, func(i, j int) bool {
|
|
return getTargetName(expectedContents[i]) < getTargetName(expectedContents[j])
|
|
})
|
|
for i, actualTarget := range actualTargets {
|
|
if w, g := expectedContents[i], actualTarget.content; w != g {
|
|
t.Errorf(
|
|
"%s[%d]: Expected generated Bazel target to be `%s`, got `%s`",
|
|
description, i, w, g)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
type nestedProps struct {
|
|
Nested_prop *string
|
|
}
|
|
|
|
type EmbeddedProps struct {
|
|
Embedded_prop *string
|
|
}
|
|
|
|
type OtherEmbeddedProps struct {
|
|
Other_embedded_prop *string
|
|
}
|
|
|
|
type customProps struct {
|
|
EmbeddedProps
|
|
*OtherEmbeddedProps
|
|
|
|
Bool_prop bool
|
|
Bool_ptr_prop *bool
|
|
// Ensure that properties tagged `blueprint:mutated` are omitted
|
|
Int_prop int `blueprint:"mutated"`
|
|
Int64_ptr_prop *int64
|
|
String_prop string
|
|
String_literal_prop *string `android:"arch_variant"`
|
|
String_ptr_prop *string
|
|
String_list_prop []string
|
|
|
|
Nested_props nestedProps
|
|
Nested_props_ptr *nestedProps
|
|
|
|
Arch_paths []string `android:"path,arch_variant"`
|
|
Arch_paths_exclude []string `android:"path,arch_variant"`
|
|
|
|
// Prop used to indicate this conversion should be 1 module -> multiple targets
|
|
One_to_many_prop *bool
|
|
|
|
Api *string // File describing the APIs of this module
|
|
|
|
Test_config_setting *bool // Used to test generation of config_setting targets
|
|
}
|
|
|
|
type customModule struct {
|
|
android.ModuleBase
|
|
android.BazelModuleBase
|
|
|
|
props customProps
|
|
}
|
|
|
|
// OutputFiles is needed because some instances of this module use dist with a
|
|
// tag property which requires the module implements OutputFileProducer.
|
|
func (m *customModule) OutputFiles(tag string) (android.Paths, error) {
|
|
return android.PathsForTesting("path" + tag), nil
|
|
}
|
|
|
|
func (m *customModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|
// nothing for now.
|
|
}
|
|
|
|
func customModuleFactoryBase() android.Module {
|
|
module := &customModule{}
|
|
module.AddProperties(&module.props)
|
|
android.InitBazelModule(module)
|
|
return module
|
|
}
|
|
|
|
func customModuleFactoryHostAndDevice() android.Module {
|
|
m := customModuleFactoryBase()
|
|
android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibBoth)
|
|
return m
|
|
}
|
|
|
|
func customModuleFactoryDeviceSupported() android.Module {
|
|
m := customModuleFactoryBase()
|
|
android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibBoth)
|
|
return m
|
|
}
|
|
|
|
func customModuleFactoryHostSupported() android.Module {
|
|
m := customModuleFactoryBase()
|
|
android.InitAndroidArchModule(m, android.HostSupported, android.MultilibBoth)
|
|
return m
|
|
}
|
|
|
|
func customModuleFactoryHostAndDeviceDefault() android.Module {
|
|
m := customModuleFactoryBase()
|
|
android.InitAndroidArchModule(m, android.HostAndDeviceDefault, android.MultilibBoth)
|
|
return m
|
|
}
|
|
|
|
func customModuleFactoryNeitherHostNorDeviceSupported() android.Module {
|
|
m := customModuleFactoryBase()
|
|
android.InitAndroidArchModule(m, android.NeitherHostNorDeviceSupported, android.MultilibBoth)
|
|
return m
|
|
}
|
|
|
|
type testProps struct {
|
|
Test_prop struct {
|
|
Test_string_prop string
|
|
}
|
|
}
|
|
|
|
type customTestModule struct {
|
|
android.ModuleBase
|
|
|
|
props customProps
|
|
test_props testProps
|
|
}
|
|
|
|
func (m *customTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|
// nothing for now.
|
|
}
|
|
|
|
func customTestModuleFactoryBase() android.Module {
|
|
m := &customTestModule{}
|
|
m.AddProperties(&m.props)
|
|
m.AddProperties(&m.test_props)
|
|
return m
|
|
}
|
|
|
|
func customTestModuleFactory() android.Module {
|
|
m := customTestModuleFactoryBase()
|
|
android.InitAndroidModule(m)
|
|
return m
|
|
}
|
|
|
|
type customDefaultsModule struct {
|
|
android.ModuleBase
|
|
android.DefaultsModuleBase
|
|
}
|
|
|
|
func customDefaultsModuleFactoryBase() android.DefaultsModule {
|
|
module := &customDefaultsModule{}
|
|
module.AddProperties(&customProps{})
|
|
return module
|
|
}
|
|
|
|
func customDefaultsModuleFactoryBasic() android.Module {
|
|
return customDefaultsModuleFactoryBase()
|
|
}
|
|
|
|
func customDefaultsModuleFactory() android.Module {
|
|
m := customDefaultsModuleFactoryBase()
|
|
android.InitDefaultsModule(m)
|
|
return m
|
|
}
|
|
|
|
type EmbeddedAttr struct {
|
|
Embedded_attr *string
|
|
}
|
|
|
|
type OtherEmbeddedAttr struct {
|
|
Other_embedded_attr *string
|
|
}
|
|
|
|
type customBazelModuleAttributes struct {
|
|
EmbeddedAttr
|
|
*OtherEmbeddedAttr
|
|
String_literal_prop bazel.StringAttribute
|
|
String_ptr_prop *string
|
|
String_list_prop []string
|
|
Arch_paths bazel.LabelListAttribute
|
|
Api bazel.LabelAttribute
|
|
}
|
|
|
|
func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
|
|
if p := m.props.One_to_many_prop; p != nil && *p {
|
|
customBp2buildOneToMany(ctx, m)
|
|
return
|
|
}
|
|
|
|
paths := bazel.LabelListAttribute{}
|
|
strAttr := bazel.StringAttribute{}
|
|
for axis, configToProps := range m.GetArchVariantProperties(ctx, &customProps{}) {
|
|
for config, props := range configToProps {
|
|
if custProps, ok := props.(*customProps); ok {
|
|
if custProps.Arch_paths != nil {
|
|
paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrcExcludes(ctx, custProps.Arch_paths, custProps.Arch_paths_exclude))
|
|
}
|
|
if custProps.String_literal_prop != nil {
|
|
strAttr.SetSelectValue(axis, config, custProps.String_literal_prop)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
productVariableProps := android.ProductVariableProperties(ctx, ctx.Module())
|
|
if props, ok := productVariableProps["String_literal_prop"]; ok {
|
|
for c, p := range props {
|
|
if val, ok := p.(*string); ok {
|
|
strAttr.SetSelectValue(c.ConfigurationAxis(), c.SelectKey(), val)
|
|
}
|
|
}
|
|
}
|
|
|
|
paths.ResolveExcludes()
|
|
|
|
attrs := &customBazelModuleAttributes{
|
|
String_literal_prop: strAttr,
|
|
String_ptr_prop: m.props.String_ptr_prop,
|
|
String_list_prop: m.props.String_list_prop,
|
|
Arch_paths: paths,
|
|
}
|
|
|
|
attrs.Embedded_attr = m.props.Embedded_prop
|
|
if m.props.OtherEmbeddedProps != nil {
|
|
attrs.OtherEmbeddedAttr = &OtherEmbeddedAttr{Other_embedded_attr: m.props.OtherEmbeddedProps.Other_embedded_prop}
|
|
}
|
|
|
|
props := bazel.BazelTargetModuleProperties{
|
|
Rule_class: "custom",
|
|
}
|
|
|
|
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
|
|
|
|
if proptools.Bool(m.props.Test_config_setting) {
|
|
m.createConfigSetting(ctx)
|
|
}
|
|
|
|
}
|
|
|
|
func (m *customModule) createConfigSetting(ctx android.TopDownMutatorContext) {
|
|
csa := bazel.ConfigSettingAttributes{
|
|
Flag_values: bazel.StringMapAttribute{
|
|
"//build/bazel/rules/my_string_setting": m.Name(),
|
|
},
|
|
}
|
|
ca := android.CommonAttributes{
|
|
Name: m.Name() + "_config_setting",
|
|
}
|
|
ctx.CreateBazelConfigSetting(
|
|
csa,
|
|
ca,
|
|
ctx.ModuleDir(),
|
|
)
|
|
}
|
|
|
|
var _ android.ApiProvider = (*customModule)(nil)
|
|
|
|
func (c *customModule) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
|
|
props := bazel.BazelTargetModuleProperties{
|
|
Rule_class: "custom_api_contribution",
|
|
}
|
|
apiAttribute := bazel.MakeLabelAttribute(
|
|
android.BazelLabelForModuleSrcSingle(ctx, proptools.String(c.props.Api)).Label,
|
|
)
|
|
attrs := &customBazelModuleAttributes{
|
|
Api: *apiAttribute,
|
|
}
|
|
ctx.CreateBazelTargetModule(props,
|
|
android.CommonAttributes{Name: c.Name()},
|
|
attrs)
|
|
}
|
|
|
|
// A bp2build mutator that uses load statements and creates a 1:M mapping from
|
|
// module to target.
|
|
func customBp2buildOneToMany(ctx android.TopDownMutatorContext, m *customModule) {
|
|
|
|
baseName := m.Name()
|
|
attrs := &customBazelModuleAttributes{}
|
|
|
|
myLibraryProps := bazel.BazelTargetModuleProperties{
|
|
Rule_class: "my_library",
|
|
Bzl_load_location: "//build/bazel/rules:rules.bzl",
|
|
}
|
|
ctx.CreateBazelTargetModule(myLibraryProps, android.CommonAttributes{Name: baseName}, attrs)
|
|
|
|
protoLibraryProps := bazel.BazelTargetModuleProperties{
|
|
Rule_class: "proto_library",
|
|
Bzl_load_location: "//build/bazel/rules:proto.bzl",
|
|
}
|
|
ctx.CreateBazelTargetModule(protoLibraryProps, android.CommonAttributes{Name: baseName + "_proto_library_deps"}, attrs)
|
|
|
|
myProtoLibraryProps := bazel.BazelTargetModuleProperties{
|
|
Rule_class: "my_proto_library",
|
|
Bzl_load_location: "//build/bazel/rules:proto.bzl",
|
|
}
|
|
ctx.CreateBazelTargetModule(myProtoLibraryProps, android.CommonAttributes{Name: baseName + "_my_proto_library_deps"}, attrs)
|
|
}
|
|
|
|
// Helper method for tests to easily access the targets in a dir.
|
|
func generateBazelTargetsForDir(codegenCtx *CodegenContext, dir string) (BazelTargets, []error) {
|
|
// TODO: Set generateFilegroups to true and/or remove the generateFilegroups argument completely
|
|
res, err := GenerateBazelTargets(codegenCtx, false)
|
|
if err != nil {
|
|
return BazelTargets{}, err
|
|
}
|
|
return res.buildFileToTargets[dir], err
|
|
}
|
|
|
|
func registerCustomModuleForBp2buildConversion(ctx *android.TestContext) {
|
|
ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
|
|
ctx.RegisterForBazelConversion()
|
|
}
|
|
|
|
func simpleModuleDoNotConvertBp2build(typ, name string) string {
|
|
return fmt.Sprintf(`
|
|
%s {
|
|
name: "%s",
|
|
bazel_module: { bp2build_available: false },
|
|
}`, typ, name)
|
|
}
|
|
|
|
type AttrNameToString map[string]string
|
|
|
|
func (a AttrNameToString) clone() AttrNameToString {
|
|
newAttrs := make(AttrNameToString, len(a))
|
|
for k, v := range a {
|
|
newAttrs[k] = v
|
|
}
|
|
return newAttrs
|
|
}
|
|
|
|
// makeBazelTargetNoRestrictions returns bazel target build file definition that can be host or
|
|
// device specific, or independent of host/device.
|
|
func makeBazelTargetHostOrDevice(typ, name string, attrs AttrNameToString, hod android.HostOrDeviceSupported) string {
|
|
if _, ok := attrs["target_compatible_with"]; !ok {
|
|
switch hod {
|
|
case android.HostSupported:
|
|
attrs["target_compatible_with"] = `select({
|
|
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
|
|
"//conditions:default": [],
|
|
})`
|
|
case android.DeviceSupported:
|
|
attrs["target_compatible_with"] = `["//build/bazel/platforms/os:android"]`
|
|
}
|
|
}
|
|
|
|
attrStrings := make([]string, 0, len(attrs)+1)
|
|
if name != "" {
|
|
attrStrings = append(attrStrings, fmt.Sprintf(` name = "%s",`, name))
|
|
}
|
|
for _, k := range android.SortedKeys(attrs) {
|
|
attrStrings = append(attrStrings, fmt.Sprintf(" %s = %s,", k, attrs[k]))
|
|
}
|
|
return fmt.Sprintf(`%s(
|
|
%s
|
|
)`, typ, strings.Join(attrStrings, "\n"))
|
|
}
|
|
|
|
// MakeBazelTargetNoRestrictions returns bazel target build file definition that does not add a
|
|
// target_compatible_with. This is useful for module types like filegroup and genrule that arch not
|
|
// arch variant
|
|
func MakeBazelTargetNoRestrictions(typ, name string, attrs AttrNameToString) string {
|
|
return makeBazelTargetHostOrDevice(typ, name, attrs, android.HostAndDeviceDefault)
|
|
}
|
|
|
|
// makeBazelTargetNoRestrictions returns bazel target build file definition that is device specific
|
|
// as this is the most common default in Soong.
|
|
func MakeBazelTarget(typ, name string, attrs AttrNameToString) string {
|
|
return makeBazelTargetHostOrDevice(typ, name, attrs, android.DeviceSupported)
|
|
}
|
|
|
|
type ExpectedRuleTarget struct {
|
|
Rule string
|
|
Name string
|
|
Attrs AttrNameToString
|
|
Hod android.HostOrDeviceSupported
|
|
}
|
|
|
|
func (ebr ExpectedRuleTarget) String() string {
|
|
return makeBazelTargetHostOrDevice(ebr.Rule, ebr.Name, ebr.Attrs, ebr.Hod)
|
|
}
|
|
|
|
func makeCcStubSuiteTargets(name string, attrs AttrNameToString) string {
|
|
if _, hasStubs := attrs["stubs_symbol_file"]; !hasStubs {
|
|
return ""
|
|
}
|
|
STUB_SUITE_ATTRS := map[string]string{
|
|
"stubs_symbol_file": "symbol_file",
|
|
"stubs_versions": "versions",
|
|
"soname": "soname",
|
|
"source_library_label": "source_library_label",
|
|
}
|
|
|
|
stubSuiteAttrs := AttrNameToString{}
|
|
for key, _ := range attrs {
|
|
if _, stubSuiteAttr := STUB_SUITE_ATTRS[key]; stubSuiteAttr {
|
|
stubSuiteAttrs[STUB_SUITE_ATTRS[key]] = attrs[key]
|
|
} else {
|
|
panic(fmt.Sprintf("unused cc_stub_suite attr %q\n", key))
|
|
}
|
|
}
|
|
return MakeBazelTarget("cc_stub_suite", name+"_stub_libs", stubSuiteAttrs)
|
|
}
|
|
|
|
func MakeNeverlinkDuplicateTarget(moduleType string, name string) string {
|
|
return MakeNeverlinkDuplicateTargetWithAttrs(moduleType, name, AttrNameToString{})
|
|
}
|
|
|
|
func MakeNeverlinkDuplicateTargetWithAttrs(moduleType string, name string, extraAttrs AttrNameToString) string {
|
|
attrs := extraAttrs
|
|
attrs["neverlink"] = `True`
|
|
attrs["exports"] = `[":` + name + `"]`
|
|
return MakeBazelTarget(moduleType, name+"-neverlink", attrs)
|
|
}
|
|
|
|
func getTargetName(targetContent string) string {
|
|
data := strings.Split(targetContent, "name = \"")
|
|
if len(data) < 2 {
|
|
return ""
|
|
} else {
|
|
endIndex := strings.Index(data[1], "\"")
|
|
return data[1][:endIndex]
|
|
}
|
|
}
|