Create config_setting per apex_name

These are created by bp2build in /build/bazel/rules/apex. Eventually
these config_settings should likely be colocated with the source apex
definition.

Another alternative was to make Bazel's apex a macro that generates a
config_setting. I did not pursue this further for now since it requires the
apex_available of every allowlisted cc_library to also be allowlisted.
This might not always be true (e.g. com.android.runtime)

Test: go test ./bp2build
Change-Id: Ibbb14b0d9c1491b3c79b7634a18d9d35b03922c1
This commit is contained in:
Spandan Das 2023-04-19 22:31:54 +00:00
parent 6a448ec1a3
commit 4242f10462
3 changed files with 100 additions and 4 deletions

View file

@ -268,9 +268,8 @@ func (ct configurationType) validateConfig(config string) {
case productVariables:
// do nothing
case osAndInApex:
if _, ok := osAndInApexMap[config]; !ok {
panic(fmt.Errorf("Unknown os+in_apex config: %s", config))
}
// do nothing
// this axis can contain additional per-apex keys
case inApex:
if _, ok := inApexMap[config]; !ok {
panic(fmt.Errorf("Unknown in_apex config: %s", config))
@ -299,7 +298,10 @@ func (ca ConfigurationAxis) SelectKey(config string) string {
}
return fmt.Sprintf("%s:%s", productVariableBazelPackage, config)
case osAndInApex:
return osAndInApexMap[config]
if ret, exists := osAndInApexMap[config]; exists {
return ret
}
return config
case inApex:
return inApexMap[config]
default:

View file

@ -4454,3 +4454,32 @@ cc_library {
},
})
}
// Test that a config_setting specific to an apex is created by cc_library.
func TestCcLibraryCreatesInApexConfigSetting(t *testing.T) {
runCcLibraryTestCase(t, Bp2buildTestCase{
Description: "cc_library creates a config_setting for each apex in apex_available",
ModuleTypeUnderTest: "cc_library",
ModuleTypeUnderTestFactory: cc.LibraryFactory,
Dir: "build/bazel/rules/apex",
Blueprint: `
cc_library {
name: "foo",
apex_available: [
"//apex_available:platform", // This will be skipped, since it is equivalent to //build/bazel/rules/apex:android-non_apex
"myapex"
],
}`,
ExpectedBazelTargets: []string{
MakeBazelTargetNoRestrictions(
"config_setting",
"android-in_myapex",
AttrNameToString{
"flag_values": `{
"//build/bazel/rules/apex:apex_name": "myapex",
}`,
},
),
},
})
}

View file

@ -17,6 +17,7 @@ import (
"fmt"
"path/filepath"
"strings"
"sync"
"android/soong/android"
"android/soong/bazel"
@ -1196,6 +1197,63 @@ func availableToSameApexes(a, b []string) bool {
return !differ
}
var (
apexConfigSettingKey = android.NewOnceKey("apexConfigSetting")
apexConfigSettingLock sync.Mutex
)
func getApexConfigSettingMap(config android.Config) *map[string]bool {
return config.Once(apexConfigSettingKey, func() interface{} {
return &map[string]bool{}
}).(*map[string]bool)
}
// Create a config setting for this apex in build/bazel/rules/apex
// The use case for this is stub/impl selection in cc libraries
// Long term, these config_setting(s) should be colocated with the respective apex definitions.
// Note that this is an anti-pattern: The config_setting should be created from the apex definition
// and not from a cc_library.
// This anti-pattern is needed today since not all apexes have been allowlisted.
func createInApexConfigSetting(ctx android.TopDownMutatorContext, apexName string) {
if apexName == android.AvailableToPlatform || apexName == android.AvailableToAnyApex {
// These correspond to android-non_apex and android-in_apex
return
}
apexConfigSettingLock.Lock()
defer apexConfigSettingLock.Unlock()
// Return if a config_setting has already been created
acsm := getApexConfigSettingMap(ctx.Config())
if _, exists := (*acsm)[apexName]; exists {
return
}
(*acsm)[apexName] = true
csa := bazel.ConfigSettingAttributes{
Flag_values: bazel.StringMapAttribute{
"//build/bazel/rules/apex:apex_name": apexName,
},
}
ca := android.CommonAttributes{
Name: "android-in_" + apexName,
}
ctx.CreateBazelConfigSetting(
csa,
ca,
"build/bazel/rules/apex",
)
}
func inApexConfigSetting(apexAvailable string) string {
if apexAvailable == android.AvailableToPlatform {
return bazel.AndroidAndNonApex
}
if apexAvailable == android.AvailableToAnyApex {
return bazel.AndroidAndInApex
}
return "//build/bazel/rules/apex:android-in_" + apexAvailable
}
func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis,
config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int, buildNonApexWithStubs bool) {
@ -1241,6 +1299,13 @@ func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.C
dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue))
}
}
// Create a config_setting for each apex_available.
// This will be used to select impl of a dep if dep is available to the same apex.
for _, aa := range apexAvailable {
createInApexConfigSetting(ctx.(android.TopDownMutatorContext), aa)
}
}
func (la *linkerAttributes) convertStripProps(ctx android.BazelConversionPathContext, module *Module) {