From b6a55bf065a4c1d0dfb7f4f9638f1333de3e183e Mon Sep 17 00:00:00 2001 From: Liz Kammer Date: Mon, 12 Apr 2021 15:42:51 -0400 Subject: [PATCH] Incorporate cc_library_headers into mixed builds Test: go soong tests Test: bp2build generate & sync; mixed build libc; mixed build su (su is an Android.mk target that relies on converted a cc_library_headers) Bug: 181552740 Change-Id: I9efd587970551fd41f642a208f0aa0a80e8694e0 --- android/bazel_paths.go | 10 +++++++ bazel/cquery/request_type.go | 13 ++++++++- bazel/cquery/request_type_test.go | 19 +++++++++---- cc/androidmk.go | 22 ++++++++++++--- cc/library.go | 3 +- cc/library_headers.go | 47 +++++++++++++++++++++++++++++++ cc/library_sdk_member.go | 9 +++++- cc/linkable.go | 13 +++++++++ 8 files changed, 123 insertions(+), 13 deletions(-) diff --git a/android/bazel_paths.go b/android/bazel_paths.go index 9727cc7fe..63e2c50ed 100644 --- a/android/bazel_paths.go +++ b/android/bazel_paths.go @@ -351,3 +351,13 @@ func PathForBazelOut(ctx PathContext, paths ...string) BazelOutPath { OutputPath: outputPath.withRel(validatedExecRootPath), } } + +// PathsForBazelOut returns a list of paths representing the paths under an output directory +// dedicated to Bazel-owned outputs. +func PathsForBazelOut(ctx PathContext, paths []string) Paths { + outs := make(Paths, 0, len(paths)) + for _, p := range paths { + outs = append(outs, PathForBazelOut(ctx, p)) + } + return outs +} diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go index 80491089d..c30abeb87 100644 --- a/bazel/cquery/request_type.go +++ b/bazel/cquery/request_type.go @@ -14,6 +14,8 @@ type CcInfo struct { OutputFiles []string CcObjectFiles []string CcStaticLibraryFiles []string + Includes []string + SystemIncludes []string } type getOutputFilesRequestType struct{} @@ -63,6 +65,9 @@ func (g getCcInfoType) StarlarkFunctionBody() string { return ` outputFiles = [f.path for f in target.files.to_list()] +includes = providers(target)["CcInfo"].compilation_context.includes.to_list() +system_includes = providers(target)["CcInfo"].compilation_context.system_includes.to_list() + ccObjectFiles = [] staticLibraries = [] linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list() @@ -78,6 +83,8 @@ returns = [ outputFiles, staticLibraries, ccObjectFiles, + includes, + system_includes, ] return "|".join([", ".join(r) for r in returns])` @@ -91,7 +98,7 @@ func (g getCcInfoType) ParseResult(rawString string) (CcInfo, error) { var ccObjects []string splitString := strings.Split(rawString, "|") - if expectedLen := 3; len(splitString) != expectedLen { + if expectedLen := 5; len(splitString) != expectedLen { return CcInfo{}, fmt.Errorf("Expected %d items, got %q", expectedLen, splitString) } outputFilesString := splitString[0] @@ -100,10 +107,14 @@ func (g getCcInfoType) ParseResult(rawString string) (CcInfo, error) { outputFiles = splitOrEmpty(outputFilesString, ", ") ccStaticLibraries := splitOrEmpty(ccStaticLibrariesString, ", ") ccObjects = splitOrEmpty(ccObjectsString, ", ") + includes := splitOrEmpty(splitString[3], ", ") + systemIncludes := splitOrEmpty(splitString[4], ", ") return CcInfo{ OutputFiles: outputFiles, CcObjectFiles: ccObjects, CcStaticLibraryFiles: ccStaticLibraries, + Includes: includes, + SystemIncludes: systemIncludes, }, nil } diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go index 48edb9049..6369999fb 100644 --- a/bazel/cquery/request_type_test.go +++ b/bazel/cquery/request_type_test.go @@ -3,6 +3,7 @@ package cquery import ( "fmt" "reflect" + "strings" "testing" ) @@ -45,42 +46,48 @@ func TestGetCcInfoParseResults(t *testing.T) { }{ { description: "no result", - input: "||", + input: "||||", expectedOutput: CcInfo{ OutputFiles: []string{}, CcObjectFiles: []string{}, CcStaticLibraryFiles: []string{}, + Includes: []string{}, + SystemIncludes: []string{}, }, }, { description: "only output", - input: "test||", + input: "test||||", expectedOutput: CcInfo{ OutputFiles: []string{"test"}, CcObjectFiles: []string{}, CcStaticLibraryFiles: []string{}, + Includes: []string{}, + SystemIncludes: []string{}, }, }, { description: "all items set", - input: "out1, out2|static_lib1, static_lib2|object1, object2", + input: "out1, out2|static_lib1, static_lib2|object1, object2|., dir/subdir|system/dir, system/other/dir", expectedOutput: CcInfo{ OutputFiles: []string{"out1", "out2"}, CcObjectFiles: []string{"object1", "object2"}, CcStaticLibraryFiles: []string{"static_lib1", "static_lib2"}, + Includes: []string{".", "dir/subdir"}, + SystemIncludes: []string{"system/dir", "system/other/dir"}, }, }, { description: "too few result splits", input: "|", expectedOutput: CcInfo{}, - expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 3, []string{"", ""}), + expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 5, []string{"", ""}), }, { description: "too many result splits", - input: "|||", + input: strings.Repeat("|", 8), expectedOutput: CcInfo{}, - expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 3, []string{"", "", "", ""}), + expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 5, make([]string, 9)), }, } for _, tc := range testCases { diff --git a/cc/androidmk.go b/cc/androidmk.go index 536efa433..8f3a652e6 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -191,17 +191,31 @@ func makeOverrideModuleNames(ctx AndroidMkContext, overrides []string) []string } func (library *libraryDecorator) androidMkWriteExportedFlags(entries *android.AndroidMkEntries) { - exportedFlags := library.flagExporter.flags - for _, dir := range library.flagExporter.dirs { + var exportedFlags []string + var includeDirs android.Paths + var systemIncludeDirs android.Paths + var exportedDeps android.Paths + + if library.flagExporterInfo != nil { + exportedFlags = library.flagExporterInfo.Flags + includeDirs = library.flagExporterInfo.IncludeDirs + systemIncludeDirs = library.flagExporterInfo.SystemIncludeDirs + exportedDeps = library.flagExporterInfo.Deps + } else { + exportedFlags = library.flagExporter.flags + includeDirs = library.flagExporter.dirs + systemIncludeDirs = library.flagExporter.systemDirs + exportedDeps = library.flagExporter.deps + } + for _, dir := range includeDirs { exportedFlags = append(exportedFlags, "-I"+dir.String()) } - for _, dir := range library.flagExporter.systemDirs { + for _, dir := range systemIncludeDirs { exportedFlags = append(exportedFlags, "-isystem "+dir.String()) } if len(exportedFlags) > 0 { entries.AddStrings("LOCAL_EXPORT_CFLAGS", exportedFlags...) } - exportedDeps := library.flagExporter.deps if len(exportedDeps) > 0 { entries.AddStrings("LOCAL_EXPORT_C_INCLUDE_DEPS", exportedDeps.Strings()...) } diff --git a/cc/library.go b/cc/library.go index 9a2b02e0c..0b21a0813 100644 --- a/cc/library.go +++ b/cc/library.go @@ -426,7 +426,8 @@ type libraryDecorator struct { tocFile android.OptionalPath flagExporter - stripper Stripper + flagExporterInfo *FlagExporterInfo + stripper Stripper // For whole_static_libs objects Objects diff --git a/cc/library_headers.go b/cc/library_headers.go index 078242fab..f2cb52baf 100644 --- a/cc/library_headers.go +++ b/cc/library_headers.go @@ -43,6 +43,52 @@ func RegisterLibraryHeadersBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("cc_prebuilt_library_headers", prebuiltLibraryHeaderFactory) } +type libraryHeaderBazelHander struct { + bazelHandler + + module *Module + library *libraryDecorator +} + +func (h *libraryHeaderBazelHander) generateBazelBuildActions(ctx android.ModuleContext, label string) bool { + bazelCtx := ctx.Config().BazelContext + ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType) + if err != nil { + ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err) + return false + } + if !ok { + return false + } + + outputPaths := ccInfo.OutputFiles + if len(outputPaths) != 1 { + ctx.ModuleErrorf("expected exactly one output file for %q, but got %q", label, outputPaths) + return false + } + + outputPath := android.PathForBazelOut(ctx, outputPaths[0]) + h.module.outputFile = android.OptionalPathForPath(outputPath) + + // HeaderLibraryInfo is an empty struct to indicate to dependencies that this is a header library + ctx.SetProvider(HeaderLibraryInfoProvider, HeaderLibraryInfo{}) + + flagExporterInfo := flagExporterInfoFromCcInfo(ctx, ccInfo) + // Store flag info to be passed along to androimk + // TODO(b/184387147): Androidmk should be done in Bazel, not Soong. + h.library.flagExporterInfo = &flagExporterInfo + // flag exporters consolidates properties like includes, flags, dependencies that should be + // exported from this module to other modules + ctx.SetProvider(FlagExporterInfoProvider, flagExporterInfo) + + // Dependencies on this library will expect collectedSnapshotHeaders to be set, otherwise + // validation will fail. For now, set this to an empty list. + // TODO(cparsons): More closely mirror the collectHeadersForSnapshot implementation. + h.library.collectedSnapshotHeaders = android.Paths{} + + return true +} + // cc_library_headers contains a set of c/c++ headers which are imported by // other soong cc modules using the header_libs property. For best practices, // use export_include_dirs property or LOCAL_EXPORT_C_INCLUDE_DIRS for @@ -51,6 +97,7 @@ func LibraryHeaderFactory() android.Module { module, library := NewLibrary(android.HostAndDeviceSupported) library.HeaderOnly() module.sdkMemberTypes = []android.SdkMemberType{headersLibrarySdkMemberType} + module.bazelHandler = &libraryHeaderBazelHander{module: module, library: library} return module.Init() } diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go index d5f2adf8b..9010a1a89 100644 --- a/cc/library_sdk_member.go +++ b/cc/library_sdk_member.go @@ -162,9 +162,16 @@ func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMembe return &nativeLibInfoProperties{memberType: mt} } +func isBazelOutDirectory(p android.Path) bool { + _, bazel := p.(android.BazelOutPath) + return bazel +} + func isGeneratedHeaderDirectory(p android.Path) bool { _, gen := p.(android.WritablePath) - return gen + // TODO(b/183213331): Here we assume that bazel-based headers are not generated; we need + // to support generated headers in mixed builds. + return gen && !isBazelOutDirectory(p) } type includeDirsProperty struct { diff --git a/cc/linkable.go b/cc/linkable.go index 0fb9c0944..2fa12f61c 100644 --- a/cc/linkable.go +++ b/cc/linkable.go @@ -2,6 +2,7 @@ package cc import ( "android/soong/android" + "android/soong/bazel/cquery" "github.com/google/blueprint" ) @@ -274,3 +275,15 @@ type FlagExporterInfo struct { } var FlagExporterInfoProvider = blueprint.NewProvider(FlagExporterInfo{}) + +// flagExporterInfoFromCcInfo populates FlagExporterInfo provider with information from Bazel. +func flagExporterInfoFromCcInfo(ctx android.ModuleContext, ccInfo cquery.CcInfo) FlagExporterInfo { + + includes := android.PathsForBazelOut(ctx, ccInfo.Includes) + systemIncludes := android.PathsForBazelOut(ctx, ccInfo.SystemIncludes) + + return FlagExporterInfo{ + IncludeDirs: includes, + SystemIncludeDirs: systemIncludes, + } +}