diff --git a/apex/apex.go b/apex/apex.go index 6a64ad6cd..33ed11199 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -3700,6 +3700,8 @@ func convertWithBp2build(a *apexBundle, ctx android.TopDownMutatorContext) (baze commonAttrs := android.CommonAttributes{} if a.testApex { commonAttrs.Testonly = proptools.BoolPtr(true) + // Set the api_domain of the test apex + attrs.Base_apex_name = proptools.StringPtr(cc.GetApiDomain(a.Name())) } return attrs, props, commonAttrs diff --git a/bazel/configurability.go b/bazel/configurability.go index 8f4f965f3..d042fe8b8 100644 --- a/bazel/configurability.go +++ b/bazel/configurability.go @@ -69,8 +69,8 @@ const ( productVariableBazelPackage = "//build/bazel/product_variables" - AndroidAndInApex = "android-in_apex" - AndroidAndNonApex = "android-non_apex" + AndroidAndInApex = "android-in_apex" + AndroidPlatform = "system" InApex = "in_apex" NonApex = "non_apex" @@ -202,7 +202,7 @@ var ( osAndInApexMap = map[string]string{ AndroidAndInApex: "//build/bazel/rules/apex:android-in_apex", - AndroidAndNonApex: "//build/bazel/rules/apex:android-non_apex", + AndroidPlatform: "//build/bazel/rules/apex:system", osDarwin: "//build/bazel/platforms/os:darwin", osLinux: "//build/bazel/platforms/os:linux_glibc", osLinuxMusl: "//build/bazel/platforms/os:linux_musl", diff --git a/bazel/properties.go b/bazel/properties.go index 77db1c4ec..e22f4dbe7 100644 --- a/bazel/properties.go +++ b/bazel/properties.go @@ -1434,4 +1434,6 @@ type StringMapAttribute map[string]string type ConfigSettingAttributes struct { // Each key in Flag_values is a label to a custom string_setting Flag_values StringMapAttribute + // Each element in Constraint_values is a label to a constraint_value + Constraint_values LabelListAttribute } diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go index 1cc3f22ed..390cabe1f 100644 --- a/bp2build/apex_conversion_test.go +++ b/bp2build/apex_conversion_test.go @@ -1475,10 +1475,11 @@ apex_test { `, ExpectedBazelTargets: []string{ MakeBazelTarget("apex", "test_com.android.apogee", AttrNameToString{ - "file_contexts": `"file_contexts_file"`, - "manifest": `"apex_manifest.json"`, - "testonly": `True`, - "tests": `[":cc_test_1"]`, + "file_contexts": `"file_contexts_file"`, + "base_apex_name": `"com.android.apogee"`, + "manifest": `"apex_manifest.json"`, + "testonly": `True`, + "tests": `[":cc_test_1"]`, }), }}) } diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go index 1b64055f7..e127fd542 100644 --- a/bp2build/build_conversion_test.go +++ b/bp2build/build_conversion_test.go @@ -21,6 +21,7 @@ import ( "android/soong/android" "android/soong/android/allowlists" + "android/soong/bazel" "android/soong/python" ) @@ -1931,3 +1932,17 @@ func TestGenerateConfigSetting(t *testing.T) { Description: "Generating API contribution Bazel targets for custom module", }) } + +// If values of all keys in an axis are equal to //conditions:default, drop the axis and print the common value +func TestPrettyPrintSelectMapEqualValues(t *testing.T) { + lla := bazel.LabelListAttribute{ + Value: bazel.LabelList{}, + } + libFooImplLabel := bazel.Label{ + Label: ":libfoo.impl", + } + lla.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidPlatform, bazel.MakeLabelList([]bazel.Label{libFooImplLabel})) + lla.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.MakeLabelList([]bazel.Label{libFooImplLabel})) + actual, _ := prettyPrintAttribute(lla, 0) + android.AssertStringEquals(t, "Print the common value if all keys in an axis have the same value", `[":libfoo.impl"]`, actual) +} diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go index 776129f58..1b681efb0 100644 --- a/bp2build/cc_library_conversion_test.go +++ b/bp2build/cc_library_conversion_test.go @@ -3042,7 +3042,8 @@ cc_library { }`, ExpectedBazelTargets: makeCcLibraryTargets("foolib", AttrNameToString{ "implementation_dynamic_deps": `select({ - "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:barlib"], + "//build/bazel/rules/apex:foo": ["@api_surfaces//module-libapi/current:barlib"], + "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:barlib"], "//conditions:default": [":barlib"], })`, "local_includes": `["."]`, @@ -3096,7 +3097,11 @@ cc_library { "//build/bazel/platforms/os:linux_glibc": [":quxlib"], "//build/bazel/platforms/os:linux_musl": [":quxlib"], "//build/bazel/platforms/os:windows": [":quxlib"], - "//build/bazel/rules/apex:android-in_apex": [ + "//build/bazel/rules/apex:foo": [ + "@api_surfaces//module-libapi/current:barlib", + "@api_surfaces//module-libapi/current:quxlib", + ], + "//build/bazel/rules/apex:system": [ "@api_surfaces//module-libapi/current:barlib", "@api_surfaces//module-libapi/current:quxlib", ], @@ -4139,44 +4144,34 @@ cc_library { name: "barlib", stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] }, bazel_module: { bp2build_available: false }, + apex_available: ["//apex_available:platform",], } cc_library { name: "bazlib", stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] }, bazel_module: { bp2build_available: false }, + apex_available: ["//apex_available:platform",], } cc_library { name: "foo", shared_libs: ["barlib", "bazlib"], export_shared_lib_headers: ["bazlib"], apex_available: [ - "apex_available:platform", + "//apex_available:platform", ], }`, ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{ - "implementation_dynamic_deps": `select({ - "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:barlib"], - "//conditions:default": [":barlib"], - })`, - "dynamic_deps": `select({ - "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:bazlib"], - "//conditions:default": [":bazlib"], - })`, - "local_includes": `["."]`, - "tags": `["apex_available=apex_available:platform"]`, + "implementation_dynamic_deps": `[":barlib"]`, + "dynamic_deps": `[":bazlib"]`, + "local_includes": `["."]`, + "tags": `["apex_available=//apex_available:platform"]`, }), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{ - "implementation_dynamic_deps": `select({ - "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:barlib"], - "//conditions:default": [":barlib"], - })`, - "dynamic_deps": `select({ - "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:bazlib"], - "//conditions:default": [":bazlib"], - })`, - "local_includes": `["."]`, - "tags": `["apex_available=apex_available:platform"]`, + "implementation_dynamic_deps": `[":barlib"]`, + "dynamic_deps": `[":bazlib"]`, + "local_includes": `["."]`, + "tags": `["apex_available=//apex_available:platform"]`, }), }, }) @@ -4473,11 +4468,12 @@ cc_library { ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions( "config_setting", - "android-in_myapex", + "myapex", AttrNameToString{ "flag_values": `{ - "//build/bazel/rules/apex:apex_name": "myapex", + "//build/bazel/rules/apex:api_domain": "myapex", }`, + "constraint_values": `["//build/bazel/platforms/os:android"]`, }, ), }, diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go index 47dff8a57..2ee9c99f9 100644 --- a/bp2build/cc_library_shared_conversion_test.go +++ b/bp2build/cc_library_shared_conversion_test.go @@ -609,7 +609,8 @@ cc_library_shared { ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_shared", "b", AttrNameToString{ "implementation_dynamic_deps": `select({ - "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:a"], + "//build/bazel/rules/apex:apex_b": ["@api_surfaces//module-libapi/current:a"], + "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:a"], "//conditions:default": [":a"], })`, "tags": `["apex_available=apex_b"]`, @@ -618,6 +619,64 @@ cc_library_shared { }) } +// Tests that library in apexfoo links against stubs of platform_lib and otherapex_lib +func TestCcLibrarySharedStubs_UseStubsFromMultipleApiDomains(t *testing.T) { + runCcLibrarySharedTestCase(t, Bp2buildTestCase{ + Description: "cc_library_shared stubs", + ModuleTypeUnderTest: "cc_library_shared", + ModuleTypeUnderTestFactory: cc.LibrarySharedFactory, + Blueprint: soongCcLibrarySharedPreamble + ` +cc_library_shared { + name: "libplatform_stable", + stubs: { symbol_file: "libplatform_stable.map.txt", versions: ["28", "29", "current"] }, + apex_available: ["//apex_available:platform"], + bazel_module: { bp2build_available: false }, + include_build_directory: false, +} +cc_library_shared { + name: "libapexfoo_stable", + stubs: { symbol_file: "libapexfoo_stable.map.txt", versions: ["28", "29", "current"] }, + apex_available: ["apexfoo"], + bazel_module: { bp2build_available: false }, + include_build_directory: false, +} +cc_library_shared { + name: "libutils", + shared_libs: ["libplatform_stable", "libapexfoo_stable",], + apex_available: ["//apex_available:platform", "apexfoo", "apexbar"], + include_build_directory: false, +} +`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("cc_library_shared", "libutils", AttrNameToString{ + "implementation_dynamic_deps": `select({ + "//build/bazel/rules/apex:apexbar": [ + "@api_surfaces//module-libapi/current:libplatform_stable", + "@api_surfaces//module-libapi/current:libapexfoo_stable", + ], + "//build/bazel/rules/apex:apexfoo": [ + "@api_surfaces//module-libapi/current:libplatform_stable", + ":libapexfoo_stable", + ], + "//build/bazel/rules/apex:system": [ + "@api_surfaces//module-libapi/current:libplatform_stable", + "@api_surfaces//module-libapi/current:libapexfoo_stable", + ], + "//conditions:default": [ + ":libplatform_stable", + ":libapexfoo_stable", + ], + })`, + "tags": `[ + "apex_available=//apex_available:platform", + "apex_available=apexfoo", + "apex_available=apexbar", + ]`, + }), + }, + }) +} + func TestCcLibrarySharedStubs_IgnorePlatformAvailable(t *testing.T) { runCcLibrarySharedTestCase(t, Bp2buildTestCase{ Description: "cc_library_shared stubs", @@ -641,7 +700,8 @@ cc_library_shared { ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_shared", "b", AttrNameToString{ "implementation_dynamic_deps": `select({ - "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:a"], + "//build/bazel/rules/apex:apex_b": ["@api_surfaces//module-libapi/current:a"], + "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:a"], "//conditions:default": [":a"], })`, "tags": `[ @@ -653,6 +713,34 @@ cc_library_shared { }) } +func TestCcLibraryDoesNotDropStubDepIfNoVariationAcrossAxis(t *testing.T) { + runCcLibrarySharedTestCase(t, Bp2buildTestCase{ + Description: "cc_library depeends on impl for all configurations", + ModuleTypeUnderTest: "cc_library_shared", + ModuleTypeUnderTestFactory: cc.LibrarySharedFactory, + Blueprint: soongCcLibrarySharedPreamble + ` +cc_library_shared { + name: "a", + stubs: { symbol_file: "a.map.txt", versions: ["28", "29", "current"] }, + bazel_module: { bp2build_available: false }, + apex_available: ["//apex_available:platform"], +} +cc_library_shared { + name: "b", + shared_libs: [":a"], + include_build_directory: false, + apex_available: ["//apex_available:platform"], +} +`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("cc_library_shared", "b", AttrNameToString{ + "implementation_dynamic_deps": `[":a"]`, + "tags": `["apex_available=//apex_available:platform"]`, + }), + }, + }) +} + func TestCcLibrarySharedStubs_MultipleApexAvailable(t *testing.T) { runCcLibrarySharedTestCase(t, Bp2buildTestCase{ ModuleTypeUnderTest: "cc_library_shared", @@ -682,7 +770,7 @@ cc_library_shared { ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_shared", "b", AttrNameToString{ "implementation_dynamic_deps": `select({ - "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:a"], + "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:a"], "//conditions:default": [":a"], })`, "tags": `[ diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go index 948801486..2705aafe5 100644 --- a/bp2build/cc_library_static_conversion_test.go +++ b/bp2build/cc_library_static_conversion_test.go @@ -1504,6 +1504,7 @@ cc_library { versions: ["current"], }, bazel_module: { bp2build_available: false }, + apex_available: ["com.android.runtime"], } cc_library_static { @@ -1561,7 +1562,8 @@ cc_library_static { }), MakeBazelTarget("cc_library_static", "keep_with_stubs", AttrNameToString{ "implementation_dynamic_deps": `select({ - "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:libm"], + "//build/bazel/rules/apex:foo": ["@api_surfaces//module-libapi/current:libm"], + "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:libm"], "//conditions:default": [":libm"], })`, "system_dynamic_deps": `[]`, diff --git a/bp2build/configurability.go b/bp2build/configurability.go index 8e171031c..3d9f0a274 100644 --- a/bp2build/configurability.go +++ b/bp2build/configurability.go @@ -279,6 +279,10 @@ func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue *stri } if len(selects) == 0 { + // If there is a default value, and there are no selects for this axis, print that without any selects. + if val, exists := selectMap[bazel.ConditionsDefaultSelectKey]; exists { + return prettyPrint(val, indent, emitZeroValues) + } // No conditions (or all values are empty lists), so no need for a map. return "", nil } diff --git a/cc/bp2build.go b/cc/bp2build.go index 3bb00adee..cf5f74d4d 100644 --- a/cc/bp2build.go +++ b/cc/bp2build.go @@ -1194,16 +1194,34 @@ func availableToSameApexes(a, b []string) bool { } var ( - apexConfigSettingKey = android.NewOnceKey("apexConfigSetting") - apexConfigSettingLock sync.Mutex + apiDomainConfigSettingKey = android.NewOnceKey("apiDomainConfigSettingKey") + apiDomainConfigSettingLock sync.Mutex ) -func getApexConfigSettingMap(config android.Config) *map[string]bool { - return config.Once(apexConfigSettingKey, func() interface{} { +func getApiDomainConfigSettingMap(config android.Config) *map[string]bool { + return config.Once(apiDomainConfigSettingKey, func() interface{} { return &map[string]bool{} }).(*map[string]bool) } +var ( + testApexNameToApiDomain = map[string]string{ + "test_broken_com.android.art": "com.android.art", + } +) + +// GetApiDomain returns the canonical name of the apex. This is synonymous to the apex_name definition. +// https://cs.android.com/android/_/android/platform/build/soong/+/e3f0281b8897da1fe23b2f4f3a05f1dc87bcc902:apex/prebuilt.go;l=81-83;drc=2dc7244af985a6ad701b22f1271e606cabba527f;bpv=1;bpt=0 +// For test apexes, it uses a naming convention heuristic to determine the api domain. +// TODO (b/281548611): Move this build/soong/android +func GetApiDomain(apexName string) string { + if apiDomain, exists := testApexNameToApiDomain[apexName]; exists { + return apiDomain + } + // Remove `test_` prefix + return strings.TrimPrefix(apexName, "test_") +} + // 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. @@ -1215,23 +1233,32 @@ func createInApexConfigSetting(ctx android.TopDownMutatorContext, apexName strin // These correspond to android-non_apex and android-in_apex return } - apexConfigSettingLock.Lock() - defer apexConfigSettingLock.Unlock() + apiDomainConfigSettingLock.Lock() + defer apiDomainConfigSettingLock.Unlock() // Return if a config_setting has already been created - acsm := getApexConfigSettingMap(ctx.Config()) - if _, exists := (*acsm)[apexName]; exists { + apiDomain := GetApiDomain(apexName) + acsm := getApiDomainConfigSettingMap(ctx.Config()) + if _, exists := (*acsm)[apiDomain]; exists { return } - (*acsm)[apexName] = true + (*acsm)[apiDomain] = true csa := bazel.ConfigSettingAttributes{ Flag_values: bazel.StringMapAttribute{ - "//build/bazel/rules/apex:apex_name": apexName, + "//build/bazel/rules/apex:api_domain": apiDomain, }, + // Constraint this to android + Constraint_values: bazel.MakeLabelListAttribute( + bazel.MakeLabelList( + []bazel.Label{ + bazel.Label{Label: "//build/bazel/platforms/os:android"}, + }, + ), + ), } ca := android.CommonAttributes{ - Name: "android-in_" + apexName, + Name: apiDomain, } ctx.CreateBazelConfigSetting( csa, @@ -1242,66 +1269,111 @@ func createInApexConfigSetting(ctx android.TopDownMutatorContext, apexName strin func inApexConfigSetting(apexAvailable string) string { if apexAvailable == android.AvailableToPlatform { - return bazel.AndroidAndNonApex + return bazel.AndroidPlatform } if apexAvailable == android.AvailableToAnyApex { return bazel.AndroidAndInApex } - return "//build/bazel/rules/apex:android-in_" + apexAvailable + apiDomain := GetApiDomain(apexAvailable) + return "//build/bazel/rules/apex:" + apiDomain +} + +// Inputs to stub vs impl selection. +type stubSelectionInfo struct { + // Label of the implementation library (e.g. //bionic/libc:libc) + impl bazel.Label + // Axis containing the implementation library + axis bazel.ConfigurationAxis + // Axis key containing the implementation library + config string + // API domain of the apex + // For test apexes (test_com.android.foo), this will be the source apex (com.android.foo) + apiDomain string + // List of dep labels + dynamicDeps *bazel.LabelListAttribute + // Boolean value for determining if the dep is in the same api domain + // If false, the label will be rewritten to to the stub label + sameApiDomain bool +} + +func useStubOrImplInApexWithName(ssi stubSelectionInfo) { + lib := ssi.impl + if !ssi.sameApiDomain { + lib = bazel.Label{ + Label: apiSurfaceModuleLibCurrentPackage + strings.TrimPrefix(lib.OriginalModuleName, ":"), + } + } + // Create a select statement specific to this apex + inApexSelectValue := ssi.dynamicDeps.SelectValue(bazel.OsAndInApexAxis, inApexConfigSetting(ssi.apiDomain)) + (&inApexSelectValue).Append(bazel.MakeLabelList([]bazel.Label{lib})) + ssi.dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, inApexConfigSetting(ssi.apiDomain), bazel.FirstUniqueBazelLabelList(inApexSelectValue)) + // Delete the library from the common config for this apex + implDynamicDeps := ssi.dynamicDeps.SelectValue(ssi.axis, ssi.config) + implDynamicDeps = bazel.SubtractBazelLabelList(implDynamicDeps, bazel.MakeLabelList([]bazel.Label{ssi.impl})) + ssi.dynamicDeps.SetSelectValue(ssi.axis, ssi.config, implDynamicDeps) + if ssi.axis == bazel.NoConfigAxis { + // Set defaults. Defaults (i.e. host) should use impl and not stubs. + defaultSelectValue := ssi.dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey) + (&defaultSelectValue).Append(bazel.MakeLabelList([]bazel.Label{ssi.impl})) + ssi.dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.FirstUniqueBazelLabelList(defaultSelectValue)) + } } func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis, config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int, buildNonApexWithStubs bool) { - depsWithStubs := []bazel.Label{} - for _, l := range dynamicLibs.Includes { - dep, _ := ctx.ModuleFromName(l.OriginalModuleName) - if d, ok := dep.(*Module); ok && d.HasStubsVariants() { - depApexAvailable := d.ApexAvailable() - if !availableToSameApexes(apexAvailable, depApexAvailable) { - depsWithStubs = append(depsWithStubs, l) - } - } - } - if len(depsWithStubs) > 0 { - implDynamicDeps := bazel.SubtractBazelLabelList(dynamicLibs, bazel.MakeLabelList(depsWithStubs)) - dynamicDeps.SetSelectValue(axis, config, implDynamicDeps) - - stubLibLabels := []bazel.Label{} - for _, l := range depsWithStubs { - stubLabelInApiSurfaces := bazel.Label{ - Label: apiSurfaceModuleLibCurrentPackage + strings.TrimPrefix(l.OriginalModuleName, ":"), - } - stubLibLabels = append(stubLibLabels, stubLabelInApiSurfaces) - } - inApexSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex) - nonApexSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex) - defaultSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey) - nonApexDeps := depsWithStubs - if buildNonApexWithStubs { - nonApexDeps = stubLibLabels - } - if axis == bazel.NoConfigAxis { - (&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels)) - (&nonApexSelectValue).Append(bazel.MakeLabelList(nonApexDeps)) - (&defaultSelectValue).Append(bazel.MakeLabelList(depsWithStubs)) - dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue)) - dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue)) - dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.FirstUniqueBazelLabelList(defaultSelectValue)) - } else if config == bazel.OsAndroid { - (&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels)) - (&nonApexSelectValue).Append(bazel.MakeLabelList(nonApexDeps)) - dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue)) - 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) } + apiDomainForSelects := []string{} + for _, apex := range apexAvailable { + apiDomainForSelects = append(apiDomainForSelects, GetApiDomain(apex)) + } + // Always emit a select statement for the platform variant. + // This ensures that b build //foo --config=android works + // Soong always creates a platform variant even when the library might not be available to platform. + if !android.InList(android.AvailableToPlatform, apiDomainForSelects) { + apiDomainForSelects = append(apiDomainForSelects, android.AvailableToPlatform) + } + apiDomainForSelects = android.SortedUniqueStrings(apiDomainForSelects) + + // Create a select for each apex this library could be included in. + for _, l := range dynamicLibs.Includes { + dep, _ := ctx.ModuleFromName(l.OriginalModuleName) + if c, ok := dep.(*Module); !ok || !c.HasStubsVariants() { + continue + } + // TODO (b/280339069): Decrease the verbosity of the generated BUILD files + for _, apiDomain := range apiDomainForSelects { + var sameApiDomain bool + if apiDomain == android.AvailableToPlatform { + // Platform variants in Soong use equality of apex_available for stub/impl selection. + // https://cs.android.com/android/_/android/platform/build/soong/+/316b0158fe57ee7764235923e7c6f3d530da39c6:cc/cc.go;l=3393-3404;drc=176271a426496fa2688efe2b40d5c74340c63375;bpv=1;bpt=0 + // One of the factors behind this design choice is cc_test + // Tests only have a platform variant, and using equality of apex_available ensures + // that tests of an apex library gets its implementation and not stubs. + // TODO (b/280343104): Discuss if we can drop this special handling for platform variants. + sameApiDomain = availableToSameApexes(apexAvailable, dep.(*Module).ApexAvailable()) + if linkable, ok := ctx.Module().(LinkableInterface); ok && linkable.Bootstrap() { + sameApiDomain = true + } + } else { + sameApiDomain = android.InList(apiDomain, dep.(*Module).ApexAvailable()) + } + ssi := stubSelectionInfo{ + impl: l, + axis: axis, + config: config, + apiDomain: apiDomain, + dynamicDeps: dynamicDeps, + sameApiDomain: sameApiDomain, + } + useStubOrImplInApexWithName(ssi) + } + } } func (la *linkerAttributes) convertStripProps(ctx android.BazelConversionPathContext, module *Module) { @@ -1396,7 +1468,6 @@ func (la *linkerAttributes) finalize(ctx android.BazelConversionPathContext) { la.implementationDynamicDeps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove) la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, toRemove) - la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, toRemove) stubsToRemove := make([]bazel.Label, 0, len(la.usedSystemDynamicDepAsDynamicDep)) for _, lib := range toRemove.Includes { stubLabelInApiSurfaces := bazel.Label{ @@ -1404,7 +1475,12 @@ func (la *linkerAttributes) finalize(ctx android.BazelConversionPathContext) { } stubsToRemove = append(stubsToRemove, stubLabelInApiSurfaces) } - la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.MakeLabelList(stubsToRemove)) + // system libraries (e.g. libc, libm, libdl) belong the com.android.runtime api domain + // dedupe the stubs of these libraries from the other api domains (platform, other_apexes...) + for _, aa := range ctx.Module().(*Module).ApexAvailable() { + la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, inApexConfigSetting(aa), bazel.MakeLabelList(stubsToRemove)) + } + la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidPlatform, bazel.MakeLabelList(stubsToRemove)) } la.deps.ResolveExcludes()