diff --git a/android/testing.go b/android/testing.go index 29af71fbc..e4202ae6b 100644 --- a/android/testing.go +++ b/android/testing.go @@ -1145,7 +1145,7 @@ func AndroidMkDataForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) var p AndroidMkDataProvider var ok bool if p, ok = mod.(AndroidMkDataProvider); !ok { - t.Errorf("module does not implement AndroidMkDataProvider: " + mod.Name()) + t.Fatalf("module does not implement AndroidMkDataProvider: " + mod.Name()) } data := p.AndroidMk() data.fillInData(ctx, mod) diff --git a/android/util.go b/android/util.go index a0f716047..234bda365 100644 --- a/android/util.go +++ b/android/util.go @@ -136,6 +136,32 @@ func InList(s string, list []string) bool { return IndexList(s, list) != -1 } +func setFromList[T comparable](l []T) map[T]bool { + m := make(map[T]bool, len(l)) + for _, t := range l { + m[t] = true + } + return m +} + +// ListDifference checks if the two lists contain the same elements +func ListDifference[T comparable](l1, l2 []T) []T { + diff := []T{} + m1 := setFromList(l1) + m2 := setFromList(l2) + for _, t := range l1 { + if _, ok := m2[t]; !ok { + diff = append(diff, t) + } + } + for _, t := range l2 { + if _, ok := m1[t]; !ok { + diff = append(diff, t) + } + } + return diff +} + // Returns true if the given string s is prefixed with any string in the given prefix list. func HasAnyPrefix(s string, prefixList []string) bool { for _, prefix := range prefixList { diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go index 599ecc72d..665419100 100644 --- a/bazel/cquery/request_type.go +++ b/bazel/cquery/request_type.go @@ -14,7 +14,14 @@ var ( GetCcUnstrippedInfo = &getCcUnstrippedInfoType{} ) +type CcAndroidMkInfo struct { + LocalStaticLibs []string + LocalWholeStaticLibs []string + LocalSharedLibs []string +} + type CcInfo struct { + CcAndroidMkInfo OutputFiles []string CcObjectFiles []string CcSharedLibraryFiles []string @@ -180,20 +187,33 @@ abi_diff_info = p.get("//build/bazel/rules/abi:abi_dump.bzl%AbiDiffInfo") if abi_diff_info: abi_diff_files = [f.path for f in abi_diff_info.diff_files.to_list()] +local_static_libs = [] +local_whole_static_libs = [] +local_shared_libs = [] +androidmk_tag = "//build/bazel/rules/cc:cc_library_common.bzl%CcAndroidMkInfo" +if androidmk_tag in p: + androidmk_info = p[androidmk_tag] + local_static_libs = androidmk_info.local_static_libs + local_whole_static_libs = androidmk_info.local_whole_static_libs + local_shared_libs = androidmk_info.local_shared_libs + return json_encode({ - "OutputFiles": outputFiles, - "CcObjectFiles": ccObjectFiles, - "CcSharedLibraryFiles": sharedLibraries, - "CcStaticLibraryFiles": staticLibraries, - "Includes": includes, - "SystemIncludes": system_includes, - "Headers": headers, - "RootStaticArchives": rootStaticArchives, - "RootDynamicLibraries": rootSharedLibraries, - "TidyFiles": tidy_files, - "TocFile": toc_file, - "UnstrippedOutput": unstripped, - "AbiDiffFiles": abi_diff_files, + "OutputFiles": outputFiles, + "CcObjectFiles": ccObjectFiles, + "CcSharedLibraryFiles": sharedLibraries, + "CcStaticLibraryFiles": staticLibraries, + "Includes": includes, + "SystemIncludes": system_includes, + "Headers": headers, + "RootStaticArchives": rootStaticArchives, + "RootDynamicLibraries": rootSharedLibraries, + "TidyFiles": tidy_files, + "TocFile": toc_file, + "UnstrippedOutput": unstripped, + "AbiDiffFiles": abi_diff_files, + "LocalStaticLibs": [l for l in local_static_libs], + "LocalWholeStaticLibs": [l for l in local_whole_static_libs], + "LocalSharedLibs": [l for l in local_shared_libs], })` } @@ -298,15 +318,32 @@ func (g getCcUnstrippedInfoType) Name() string { } func (g getCcUnstrippedInfoType) StarlarkFunctionBody() string { - return `unstripped_tag = "//build/bazel/rules/cc:stripped_cc_common.bzl%CcUnstrippedInfo" + return ` p = providers(target) output_path = target.files.to_list()[0].path + unstripped = output_path +unstripped_tag = "//build/bazel/rules/cc:stripped_cc_common.bzl%CcUnstrippedInfo" if unstripped_tag in p: - unstripped = p[unstripped_tag].unstripped.files.to_list()[0].path + unstripped_info = p[unstripped_tag] + unstripped = unstripped_info.unstripped.files.to_list()[0].path + +local_static_libs = [] +local_whole_static_libs = [] +local_shared_libs = [] +androidmk_tag = "//build/bazel/rules/cc:cc_library_common.bzl%CcAndroidMkInfo" +if androidmk_tag in p: + androidmk_info = p[androidmk_tag] + local_static_libs = androidmk_info.local_static_libs + local_whole_static_libs = androidmk_info.local_whole_static_libs + local_shared_libs = androidmk_info.local_shared_libs + return json_encode({ "OutputFile": output_path, "UnstrippedOutput": unstripped, + "LocalStaticLibs": [l for l in local_static_libs], + "LocalWholeStaticLibs": [l for l in local_whole_static_libs], + "LocalSharedLibs": [l for l in local_shared_libs], }) ` } @@ -321,6 +358,7 @@ func (g getCcUnstrippedInfoType) ParseResult(rawString string) (CcUnstrippedInfo } type CcUnstrippedInfo struct { + CcAndroidMkInfo OutputFile string UnstrippedOutput string } diff --git a/cc/cc.go b/cc/cc.go index 95fb40cca..753975e1d 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -1872,7 +1872,8 @@ var ( // in any of the --bazel-mode(s). This filters at the module level and takes // precedence over the allowlists in allowlists/allowlists.go. func (c *Module) IsMixedBuildSupported(ctx android.BaseModuleContext) bool { - if c.testBinary() && !android.InList(c.Name(), mixedBuildSupportedCcTest) { + _, isForTesting := ctx.Config().BazelContext.(android.MockBazelContext) + if c.testBinary() && !android.InList(c.Name(), mixedBuildSupportedCcTest) && !isForTesting { // Per-module rollout of mixed-builds for cc_test modules. return false } @@ -1890,6 +1891,14 @@ func (c *Module) ProcessBazelQueryResponse(ctx android.ModuleContext) { bazelCtx := ctx.Config().BazelContext if ccInfo, err := bazelCtx.GetCcInfo(bazelModuleLabel, android.GetConfigKey(ctx)); err == nil { c.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles) + c.Properties.AndroidMkSharedLibs = ccInfo.LocalSharedLibs + c.Properties.AndroidMkStaticLibs = ccInfo.LocalStaticLibs + c.Properties.AndroidMkWholeStaticLibs = ccInfo.LocalWholeStaticLibs + } + if unstrippedInfo, err := bazelCtx.GetCcUnstrippedInfo(bazelModuleLabel, android.GetConfigKey(ctx)); err == nil { + c.Properties.AndroidMkSharedLibs = unstrippedInfo.LocalSharedLibs + c.Properties.AndroidMkStaticLibs = unstrippedInfo.LocalStaticLibs + c.Properties.AndroidMkWholeStaticLibs = unstrippedInfo.LocalWholeStaticLibs } c.bazelHandler.ProcessBazelQueryResponse(ctx, bazelModuleLabel) diff --git a/cc/cc_test.go b/cc/cc_test.go index 8293f2db7..39cc0730c 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -25,6 +25,7 @@ import ( "testing" "android/soong/android" + "android/soong/bazel/cquery" ) func TestMain(m *testing.M) { @@ -3028,6 +3029,32 @@ func checkStaticLibs(t *testing.T, expected []string, module *Module) { } } +func checkWholeStaticLibs(t *testing.T, expected []string, module *Module) { + t.Helper() + actual := module.Properties.AndroidMkWholeStaticLibs + if !reflect.DeepEqual(actual, expected) { + t.Errorf("incorrect whole_static_libs"+ + "\nactual: %v"+ + "\nexpected: %v", + actual, + expected, + ) + } +} + +func checkSharedLibs(t *testing.T, expected []string, module *Module) { + t.Helper() + actual := module.Properties.AndroidMkSharedLibs + if !reflect.DeepEqual(actual, expected) { + t.Errorf("incorrect shared_libs"+ + "\nactual: %v"+ + "\nexpected: %v", + actual, + expected, + ) + } +} + const staticLibAndroidBp = ` cc_library { name: "lib1", @@ -3054,6 +3081,156 @@ func TestStaticLibDepExport(t *testing.T) { checkStaticLibs(t, []string{"lib1", "libc++_static", "libc++demangle", "libclang_rt.builtins"}, module) } +func TestLibDepAndroidMkExportInMixedBuilds(t *testing.T) { + bp := ` + cc_library { + name: "static_dep", + } + cc_library { + name: "whole_static_dep", + } + cc_library { + name: "shared_dep", + } + cc_library { + name: "lib", + bazel_module: { label: "//:lib" }, + static_libs: ["static_dep"], + whole_static_libs: ["whole_static_dep"], + shared_libs: ["shared_dep"], + } + cc_test { + name: "test", + bazel_module: { label: "//:test" }, + static_libs: ["static_dep"], + whole_static_libs: ["whole_static_dep"], + shared_libs: ["shared_dep"], + gtest: false, + } + cc_binary { + name: "binary", + bazel_module: { label: "//:binary" }, + static_libs: ["static_dep"], + whole_static_libs: ["whole_static_dep"], + shared_libs: ["shared_dep"], + } + ` + + testCases := []struct { + name string + moduleName string + variant string + androidMkInfo cquery.CcAndroidMkInfo + }{ + { + name: "shared lib", + moduleName: "lib", + variant: "android_arm64_armv8-a_shared", + androidMkInfo: cquery.CcAndroidMkInfo{ + LocalStaticLibs: []string{"static_dep"}, + LocalWholeStaticLibs: []string{"whole_static_dep"}, + LocalSharedLibs: []string{"shared_dep"}, + }, + }, + { + name: "static lib", + moduleName: "lib", + variant: "android_arm64_armv8-a_static", + androidMkInfo: cquery.CcAndroidMkInfo{ + LocalStaticLibs: []string{"static_dep"}, + LocalWholeStaticLibs: []string{"whole_static_dep"}, + LocalSharedLibs: []string{"shared_dep"}, + }, + }, + { + name: "cc_test arm64", + moduleName: "test", + variant: "android_arm64_armv8-a", + androidMkInfo: cquery.CcAndroidMkInfo{ + LocalStaticLibs: []string{"static_dep"}, + LocalWholeStaticLibs: []string{"whole_static_dep"}, + LocalSharedLibs: []string{"shared_dep"}, + }, + }, + { + name: "cc_test arm", + moduleName: "test", + variant: "android_arm_armv7-a-neon", + androidMkInfo: cquery.CcAndroidMkInfo{ + LocalStaticLibs: []string{"static_dep"}, + LocalWholeStaticLibs: []string{"whole_static_dep"}, + LocalSharedLibs: []string{"shared_dep"}, + }, + }, + { + name: "cc_binary", + moduleName: "binary", + variant: "android_arm64_armv8-a", + androidMkInfo: cquery.CcAndroidMkInfo{ + LocalStaticLibs: []string{"static_dep"}, + LocalWholeStaticLibs: []string{"whole_static_dep"}, + LocalSharedLibs: []string{"shared_dep"}, + }, + }, + } + + outputBaseDir := "out/bazel" + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForCcTest, + android.FixtureModifyConfig(func(config android.Config) { + config.BazelContext = android.MockBazelContext{ + OutputBaseDir: outputBaseDir, + LabelToCcInfo: map[string]cquery.CcInfo{ + "//:lib": cquery.CcInfo{ + CcAndroidMkInfo: tc.androidMkInfo, + RootDynamicLibraries: []string{""}, + }, + "//:lib_bp2build_cc_library_static": cquery.CcInfo{ + CcAndroidMkInfo: tc.androidMkInfo, + RootStaticArchives: []string{""}, + }, + }, + LabelToCcBinary: map[string]cquery.CcUnstrippedInfo{ + "//:test": cquery.CcUnstrippedInfo{ + CcAndroidMkInfo: tc.androidMkInfo, + }, + "//:binary": cquery.CcUnstrippedInfo{ + CcAndroidMkInfo: tc.androidMkInfo, + }, + }, + } + }), + ).RunTestWithBp(t, bp) + ctx := result.TestContext + + module := ctx.ModuleForTests(tc.moduleName, tc.variant).Module().(*Module) + entries := android.AndroidMkEntriesForTest(t, ctx, module)[0] + checkStaticLibs(t, tc.androidMkInfo.LocalStaticLibs, module) + missingStaticDeps := android.ListDifference(entries.EntryMap["LOCAL_STATIC_LIBRARIES"], tc.androidMkInfo.LocalStaticLibs) + if len(missingStaticDeps) > 0 { + t.Errorf("expected LOCAL_STATIC_LIBRARIES to be %q"+ + " but was %q; difference: %q", tc.androidMkInfo.LocalStaticLibs, entries.EntryMap["LOCAL_STATIC_LIBRARIES"], missingStaticDeps) + } + + checkWholeStaticLibs(t, tc.androidMkInfo.LocalWholeStaticLibs, module) + missingWholeStaticDeps := android.ListDifference(entries.EntryMap["LOCAL_WHOLE_STATIC_LIBRARIES"], tc.androidMkInfo.LocalWholeStaticLibs) + if len(missingWholeStaticDeps) > 0 { + t.Errorf("expected LOCAL_WHOLE_STATIC_LIBRARIES to be %q"+ + " but was %q; difference: %q", tc.androidMkInfo.LocalWholeStaticLibs, entries.EntryMap["LOCAL_WHOLE_STATIC_LIBRARIES"], missingWholeStaticDeps) + } + + checkSharedLibs(t, tc.androidMkInfo.LocalSharedLibs, module) + missingSharedDeps := android.ListDifference(entries.EntryMap["LOCAL_SHARED_LIBRARIES"], tc.androidMkInfo.LocalSharedLibs) + if len(missingSharedDeps) > 0 { + t.Errorf("expected LOCAL_SHARED_LIBRARIES to be %q"+ + " but was %q; difference: %q", tc.androidMkInfo.LocalSharedLibs, entries.EntryMap["LOCAL_SHARED_LIBRARIES"], missingSharedDeps) + } + }) + } +} + var compilerFlagsTestCases = []struct { in string out bool