From 4242f1046226d5071f5e5eff18c011231eda0c44 Mon Sep 17 00:00:00 2001 From: Spandan Das Date: Wed, 19 Apr 2023 22:31:54 +0000 Subject: [PATCH] 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 --- bazel/configurability.go | 10 ++-- bp2build/cc_library_conversion_test.go | 29 ++++++++++++ cc/bp2build.go | 65 ++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 4 deletions(-) diff --git a/bazel/configurability.go b/bazel/configurability.go index 46802565c..d01877dd5 100644 --- a/bazel/configurability.go +++ b/bazel/configurability.go @@ -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: diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go index b61b0a7cf..9f78195a6 100644 --- a/bp2build/cc_library_conversion_test.go +++ b/bp2build/cc_library_conversion_test.go @@ -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", + }`, + }, + ), + }, + }) +} diff --git a/cc/bp2build.go b/cc/bp2build.go index ad9d7021d..5ba6ea039 100644 --- a/cc/bp2build.go +++ b/cc/bp2build.go @@ -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) {