Select stub/impl per apex variant
Create a select statement for every api_domain a library could be
included in. The stub/impl
selection heuristics per apex domain are
1. If dep has stubs and the api domain appears in dep's apex_available, use
impl
2. If dep has stubs and the api domain does not appear in dep's
apex_available, use stubs
(Category 3: If dep does not have stubs and the apex does not appear in
dep's apex_available, then a separate apex_available validation in Bazel
will emit an error).
Platform variants have been special-cased for now to use equality of
apex_available for stub/impl selection
Test: go test ./bp2build
Bug: 272378496
Change-Id: Ibd29efd763c8863c7e6d2a9af0da30bbde07175d
diff --git a/bazel/configurability.go b/bazel/configurability.go
index d01877d..29299e9 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -69,8 +69,8 @@
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 @@
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/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index e198a11..e127fd5 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -1941,7 +1941,7 @@
libFooImplLabel := bazel.Label{
Label: ":libfoo.impl",
}
- lla.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.MakeLabelList([]bazel.Label{libFooImplLabel}))
+ 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 6d5fd7e..1b681ef 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -3042,7 +3042,8 @@
}`,
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 @@
"//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 @@
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"]`,
}),
},
})
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index 47dff8a..2ee9c99 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -609,7 +609,8 @@
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 @@
})
}
+// 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 @@
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 @@
})
}
+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 @@
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 9488014..2705aaf 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -1504,6 +1504,7 @@
versions: ["current"],
},
bazel_module: { bp2build_available: false },
+ apex_available: ["com.android.runtime"],
}
cc_library_static {
@@ -1561,7 +1562,8 @@
}),
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/cc/bp2build.go b/cc/bp2build.go
index ca8d609..c42a7e8 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -1269,7 +1269,7 @@
func inApexConfigSetting(apexAvailable string) string {
if apexAvailable == android.AvailableToPlatform {
- return bazel.AndroidAndNonApex
+ return bazel.AndroidPlatform
}
if apexAvailable == android.AvailableToAnyApex {
return bazel.AndroidAndInApex
@@ -1278,58 +1278,99 @@
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())
+ } 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) {
@@ -1424,7 +1465,6 @@
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{
@@ -1432,7 +1472,12 @@
}
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()