Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 48cdbeba authored by Liz Kammer's avatar Liz Kammer
Browse files

Handle stubs within an apex with apex_available

Note this doesn't entirely match Soong's logic but is an improvement to
allow linking against implementation when two cc modules are
apex_available to the same module.

It is not possible to recreate the logic for "directly in" without
significant changes to bp2build as we do not add dependencies nor run
apex mutators. Rather than trying to replicate this, we would be better
off refactoring Soong to no longer support the "directly in apex" logic
and require users to correctly specify apex_available.

Bug: 272378496
Test: go test conversion tests
Change-Id: I17ac426f9b4bdad0c2ab661484e5d994f63568ce
parent 8fdb210b
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -3038,6 +3038,7 @@ cc_library {
		},
	},
	bazel_module: { bp2build_available: true },
	apex_available: ["foo"],
}`,
		ExpectedBazelTargets: makeCcLibraryTargets("foolib", AttrNameToString{
			"implementation_dynamic_deps": `select({
@@ -3045,6 +3046,7 @@ cc_library {
        "//conditions:default": [":barlib"],
    })`,
			"local_includes": `["."]`,
			"tags":           `["apex_available=foo"]`,
		}),
	})
}
@@ -3078,6 +3080,7 @@ cc_library {
	},
	include_build_directory: false,
	bazel_module: { bp2build_available: true },
	apex_available: ["foo"],
}`,
		ExpectedBazelTargets: makeCcLibraryTargets("foolib", AttrNameToString{
			"implementation_dynamic_deps": `select({
@@ -3102,6 +3105,7 @@ cc_library {
            ":quxlib",
        ],
    })`,
			"tags": `["apex_available=foo"]`,
		}),
	})
}
+145 −0
Original line number Diff line number Diff line
@@ -556,6 +556,151 @@ cc_library_shared {
	})
}

func TestCcLibrarySharedStubs_UseImplementationInSameApex(t *testing.T) {
	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
		Description:                "cc_library_shared stubs",
		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 },
	include_build_directory: false,
	apex_available: ["made_up_apex"],
}
cc_library_shared {
	name: "b",
	shared_libs: [":a"],
	include_build_directory: false,
	apex_available: ["made_up_apex"],
}
`,
		ExpectedBazelTargets: []string{
			MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
				"implementation_dynamic_deps": `[":a"]`,
				"tags":                        `["apex_available=made_up_apex"]`,
			}),
		},
	})
}

func TestCcLibrarySharedStubs_UseStubsInDifferentApex(t *testing.T) {
	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
		Description:                "cc_library_shared stubs",
		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 },
	include_build_directory: false,
	apex_available: ["apex_a"],
}
cc_library_shared {
	name: "b",
	shared_libs: [":a"],
	include_build_directory: false,
	apex_available: ["apex_b"],
}
`,
		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"],
        "//conditions:default": [":a"],
    })`,
				"tags": `["apex_available=apex_b"]`,
			}),
		},
	})
}

func TestCcLibrarySharedStubs_IgnorePlatformAvailable(t *testing.T) {
	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
		Description:                "cc_library_shared stubs",
		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 },
	include_build_directory: false,
	apex_available: ["//apex_available:platform", "apex_a"],
}
cc_library_shared {
	name: "b",
	shared_libs: [":a"],
	include_build_directory: false,
	apex_available: ["//apex_available:platform", "apex_b"],
}
`,
		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"],
        "//conditions:default": [":a"],
    })`,
				"tags": `[
        "apex_available=//apex_available:platform",
        "apex_available=apex_b",
    ]`,
			}),
		},
	})
}

func TestCcLibrarySharedStubs_MultipleApexAvailable(t *testing.T) {
	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
		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 },
	include_build_directory: false,
	apex_available: ["//apex_available:platform", "apex_a", "apex_b"],
}
cc_library_shared {
	name: "b",
	shared_libs: [":a"],
	include_build_directory: false,
	apex_available: ["//apex_available:platform", "apex_b"],
}

cc_library_shared {
	name: "c",
	shared_libs: [":a"],
	include_build_directory: false,
	apex_available: ["//apex_available:platform", "apex_a", "apex_b"],
}
`,
		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"],
        "//conditions:default": [":a"],
    })`,
				"tags": `[
        "apex_available=//apex_available:platform",
        "apex_available=apex_b",
    ]`,
			}),
			MakeBazelTarget("cc_library_shared", "c", AttrNameToString{
				"implementation_dynamic_deps": `[":a"]`,
				"tags": `[
        "apex_available=//apex_available:platform",
        "apex_available=apex_a",
        "apex_available=apex_b",
    ]`,
			}),
		},
	})
}

func TestCcLibrarySharedSystemSharedLibsSharedEmpty(t *testing.T) {
	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
		Description:                "cc_library_shared system_shared_libs empty shared default",
+16 −3
Original line number Diff line number Diff line
@@ -1517,12 +1517,14 @@ cc_library_static {
        },
    },
    include_build_directory: false,
    apex_available: ["foo"],
}

cc_library_static {
    name: "all",
    shared_libs: ["libc"],
    include_build_directory: false,
    apex_available: ["foo"],
}

cc_library_static {
@@ -1530,12 +1532,14 @@ cc_library_static {
    shared_libs: ["libc"],
    system_shared_libs: [],
    include_build_directory: false,
    apex_available: ["foo"],
}

cc_library_static {
    name: "used_with_stubs",
    shared_libs: ["libm"],
    include_build_directory: false,
    apex_available: ["foo"],
}

cc_library_static {
@@ -1543,13 +1547,17 @@ cc_library_static {
    shared_libs: ["libm"],
    system_shared_libs: [],
    include_build_directory: false,
    apex_available: ["foo"],
}
`,
		ExpectedBazelTargets: []string{
			MakeBazelTarget("cc_library_static", "all", AttrNameToString{}),
			MakeBazelTarget("cc_library_static", "all", AttrNameToString{
				"tags": `["apex_available=foo"]`,
			}),
			MakeBazelTarget("cc_library_static", "keep_for_empty_system_shared_libs", AttrNameToString{
				"implementation_dynamic_deps": `[":libc"]`,
				"system_dynamic_deps":         `[]`,
				"tags":                        `["apex_available=foo"]`,
			}),
			MakeBazelTarget("cc_library_static", "keep_with_stubs", AttrNameToString{
				"implementation_dynamic_deps": `select({
@@ -1557,9 +1565,14 @@ cc_library_static {
        "//conditions:default": [":libm"],
    })`,
				"system_dynamic_deps": `[]`,
				"tags":                `["apex_available=foo"]`,
			}),
			MakeBazelTarget("cc_library_static", "used_in_bionic_oses", AttrNameToString{
				"tags": `["apex_available=foo"]`,
			}),
			MakeBazelTarget("cc_library_static", "used_with_stubs", AttrNameToString{
				"tags": `["apex_available=foo"]`,
			}),
			MakeBazelTarget("cc_library_static", "used_in_bionic_oses", AttrNameToString{}),
			MakeBazelTarget("cc_library_static", "used_with_stubs", AttrNameToString{}),
		},
	})
}
+22 −8
Original line number Diff line number Diff line
@@ -739,7 +739,7 @@ func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module)
			if baseLinkerProps, ok := archVariantLinkerProps[axis][cfg].(*BaseLinkerProperties); ok {
				exportHdrs = baseLinkerProps.Export_generated_headers

				(&linkerAttrs).bp2buildForAxisAndConfig(ctx, module.Binary(), axis, cfg, baseLinkerProps)
				(&linkerAttrs).bp2buildForAxisAndConfig(ctx, module, axis, cfg, baseLinkerProps)
			}
			headers := maybePartitionExportedAndImplementationsDeps(ctx, !module.Binary(), allHdrs, exportHdrs, android.BazelLabelForModuleDeps)
			implementationHdrs.SetSelectValue(axis, cfg, headers.implementation)
@@ -1021,7 +1021,8 @@ func (la *linkerAttributes) resolveTargetApexProp(ctx android.BazelConversionPat
	la.implementationDeps.Append(staticExcludesLabelList)
}

func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversionPathContext, isBinary bool, axis bazel.ConfigurationAxis, config string, props *BaseLinkerProperties) {
func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversionPathContext, module *Module, axis bazel.ConfigurationAxis, config string, props *BaseLinkerProperties) {
	isBinary := module.Binary()
	// Use a single variable to capture usage of nocrt in arch variants, so there's only 1 error message for this module
	var axisFeatures []string

@@ -1105,8 +1106,9 @@ func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversion
		// dependencies in NoConfigAxis and OsConfigurationAxis/OsAndroid are grouped by
		// having stubs or not, so Bazel select() statement can be used to choose
		// source/stub variants of them.
		setStubsForDynamicDeps(ctx, axis, config, sharedDeps.export, &la.dynamicDeps, 0)
		setStubsForDynamicDeps(ctx, axis, config, sharedDeps.implementation, &la.implementationDynamicDeps, 1)
		apexAvailable := module.ApexAvailable()
		setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, 0)
		setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, 1)
	}

	if !BoolDefault(props.Pack_relocations, packRelocationsDefault) {
@@ -1167,15 +1169,27 @@ var (
	apiSurfaceModuleLibCurrentPackage = "@api_surfaces//" + android.ModuleLibApi.String() + "/current:"
)

func availableToSameApexes(a, b []string) bool {
	if len(a) == 0 && len(b) == 0 {
		return true
	}
	differ, _, _ := android.ListSetDifference(a, b)
	return !differ
}

func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis,
	config string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int) {
	config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int) {

	depsWithStubs := []bazel.Label{}
	for _, l := range dynamicLibs.Includes {
		dep, _ := ctx.ModuleFromName(l.OriginalModuleName)
		if m, ok := dep.(*Module); ok && m.HasStubsVariants() {
		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)
@@ -1183,7 +1197,7 @@ func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.C
		stubLibLabels := []bazel.Label{}
		for _, l := range depsWithStubs {
			stubLabelInApiSurfaces := bazel.Label{
				Label: apiSurfaceModuleLibCurrentPackage + l.OriginalModuleName,
				Label: apiSurfaceModuleLibCurrentPackage + strings.TrimPrefix(l.OriginalModuleName, ":"),
			}
			stubLibLabels = append(stubLibLabels, stubLabelInApiSurfaces)
		}
+105 −0
Original line number Diff line number Diff line
@@ -3572,6 +3572,111 @@ func TestVersionedStubs(t *testing.T) {
	}
}

func TestStubsForLibraryInMultipleApexes(t *testing.T) {
	t.Parallel()
	ctx := testCc(t, `
		cc_library_shared {
			name: "libFoo",
			srcs: ["foo.c"],
			stubs: {
				symbol_file: "foo.map.txt",
				versions: ["current"],
			},
			apex_available: ["bar", "a1"],
		}

		cc_library_shared {
			name: "libBar",
			srcs: ["bar.c"],
			shared_libs: ["libFoo"],
			apex_available: ["a1"],
		}

		cc_library_shared {
			name: "libA1",
			srcs: ["a1.c"],
			shared_libs: ["libFoo"],
			apex_available: ["a1"],
		}

		cc_library_shared {
			name: "libBarA1",
			srcs: ["bara1.c"],
			shared_libs: ["libFoo"],
			apex_available: ["bar", "a1"],
		}

		cc_library_shared {
			name: "libAnyApex",
			srcs: ["anyApex.c"],
			shared_libs: ["libFoo"],
			apex_available: ["//apex_available:anyapex"],
		}

		cc_library_shared {
			name: "libBaz",
			srcs: ["baz.c"],
			shared_libs: ["libFoo"],
			apex_available: ["baz"],
		}

		cc_library_shared {
			name: "libQux",
			srcs: ["qux.c"],
			shared_libs: ["libFoo"],
			apex_available: ["qux", "bar"],
		}`)

	variants := ctx.ModuleVariantsForTests("libFoo")
	expectedVariants := []string{
		"android_arm64_armv8-a_shared",
		"android_arm64_armv8-a_shared_current",
		"android_arm_armv7-a-neon_shared",
		"android_arm_armv7-a-neon_shared_current",
	}
	variantsMismatch := false
	if len(variants) != len(expectedVariants) {
		variantsMismatch = true
	} else {
		for _, v := range expectedVariants {
			if !inList(v, variants) {
				variantsMismatch = false
			}
		}
	}
	if variantsMismatch {
		t.Errorf("variants of libFoo expected:\n")
		for _, v := range expectedVariants {
			t.Errorf("%q\n", v)
		}
		t.Errorf(", but got:\n")
		for _, v := range variants {
			t.Errorf("%q\n", v)
		}
	}

	linkAgainstFoo := []string{"libBarA1"}
	linkAgainstFooStubs := []string{"libBar", "libA1", "libBaz", "libQux", "libAnyApex"}

	libFooPath := "libFoo/android_arm64_armv8-a_shared/libFoo.so"
	for _, lib := range linkAgainstFoo {
		libLinkRule := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld")
		libFlags := libLinkRule.Args["libFlags"]
		if !strings.Contains(libFlags, libFooPath) {
			t.Errorf("%q: %q is not found in %q", lib, libFooPath, libFlags)
		}
	}

	libFooStubPath := "libFoo/android_arm64_armv8-a_shared_current/libFoo.so"
	for _, lib := range linkAgainstFooStubs {
		libLinkRule := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld")
		libFlags := libLinkRule.Args["libFlags"]
		if !strings.Contains(libFlags, libFooStubPath) {
			t.Errorf("%q: %q is not found in %q", lib, libFooStubPath, libFlags)
		}
	}
}

func TestVersioningMacro(t *testing.T) {
	t.Parallel()
	for _, tc := range []struct{ moduleName, expected string }{