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
This commit is contained in:
Liz Kammer 2021-04-12 15:42:51 -04:00
parent 1552c7b178
commit b6a55bf065
8 changed files with 123 additions and 13 deletions

View File

@ -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
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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()...)
}

View File

@ -426,7 +426,8 @@ type libraryDecorator struct {
tocFile android.OptionalPath
flagExporter
stripper Stripper
flagExporterInfo *FlagExporterInfo
stripper Stripper
// For whole_static_libs
objects Objects

View File

@ -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()
}

View File

@ -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 {

View File

@ -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,
}
}