mixed builds for cc_static_library without deps

Test: Manual mixed builds testing of `libc` target with manually
migrated "libc_nopthread" and "libc_init_dynamic".

Change-Id: If7d67e95eca9899271b1eeb662c7c2e571f64afa
This commit is contained in:
Chris Parsons 2021-03-09 20:43:32 -05:00
parent 282671d696
commit 808d84c45d
2 changed files with 108 additions and 10 deletions

View File

@ -37,6 +37,7 @@ type CqueryRequestType int
const (
getAllFiles CqueryRequestType = iota
getCcObjectFiles
getAllFilesAndCcObjectFiles
)
// Map key to describe bazel cquery requests.
@ -58,7 +59,9 @@ type BazelContext interface {
// Retrieves these files from Bazel's CcInfo provider.
GetCcObjectFiles(label string, archType ArchType) ([]string, bool)
// TODO(cparsons): Other cquery-related methods should be added here.
// Returns the results of GetAllFiles and GetCcObjectFiles in a single query (in that order).
GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool)
// ** End cquery methods
// Issues commands to Bazel to receive results for all cquery requests
@ -116,6 +119,11 @@ func (m MockBazelContext) GetCcObjectFiles(label string, archType ArchType) ([]s
return result, ok
}
func (m MockBazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
result, ok := m.AllFiles[label]
return result, result, ok
}
func (m MockBazelContext) InvokeBazel() error {
panic("unimplemented")
}
@ -154,6 +162,22 @@ func (bazelCtx *bazelContext) GetCcObjectFiles(label string, archType ArchType)
}
}
func (bazelCtx *bazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
var allFiles []string
var ccObjects []string
result, ok := bazelCtx.cquery(label, getAllFilesAndCcObjectFiles, archType)
if ok {
bazelOutput := strings.TrimSpace(result)
splitString := strings.Split(bazelOutput, "|")
allFilesString := splitString[0]
ccObjectsString := splitString[1]
allFiles = strings.Split(allFilesString, ", ")
ccObjects = strings.Split(ccObjectsString, ", ")
}
return allFiles, ccObjects, ok
}
func (n noopBazelContext) GetAllFiles(label string, archType ArchType) ([]string, bool) {
panic("unimplemented")
}
@ -162,6 +186,10 @@ func (n noopBazelContext) GetCcObjectFiles(label string, archType ArchType) ([]s
panic("unimplemented")
}
func (n noopBazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
panic("unimplemented")
}
func (n noopBazelContext) InvokeBazel() error {
panic("unimplemented")
}
@ -253,8 +281,12 @@ func pwdPrefix() string {
return ""
}
// Issues the given bazel command with given build label and additional flags.
// Returns (stdout, stderr, error). The first and second return values are strings
// containing the stdout and stderr of the run command, and an error is returned if
// the invocation returned an error code.
func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command string, labels []string,
extraFlags ...string) (string, error) {
extraFlags ...string) (string, string, error) {
cmdFlags := []string{"--output_base=" + context.outputBase, command}
cmdFlags = append(cmdFlags, labels...)
@ -281,9 +313,10 @@ func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command st
bazelCmd.Stderr = stderr
if output, err := bazelCmd.Output(); err != nil {
return "", fmt.Errorf("bazel command failed. command: [%s], env: [%s], error [%s]", bazelCmd, bazelCmd.Env, stderr)
return "", string(stderr.Bytes()),
fmt.Errorf("bazel command failed. command: [%s], env: [%s], error [%s]", bazelCmd, bazelCmd.Env, stderr)
} else {
return string(output), nil
return string(output), string(stderr.Bytes()), nil
}
}
@ -452,6 +485,11 @@ phony_root(name = "phonyroot",
strings.Join(deps_arm, ",\n ")))
}
// Returns the file contents of the buildroot.cquery file that should be used for the cquery
// expression in order to obtain information about buildroot and its dependencies.
// The contents of this file depend on the bazelContext's requests; requests are enumerated
// and grouped by their request type. The data retrieved for each label depends on its
// request type.
func (context *bazelContext) cqueryStarlarkFileContents() []byte {
formatString := `
# This file is generated by soong_build. Do not edit.
@ -463,6 +501,13 @@ getCcObjectFilesLabels = {
%s
}
getAllFilesAndCcObjectFilesLabels = {
%s
}
def get_all_files(target):
return [f.path for f in target.files.to_list()]
def get_cc_object_files(target):
result = []
linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list()
@ -492,9 +537,11 @@ def get_arch(target):
def format(target):
id_string = str(target.label) + "|" + get_arch(target)
if id_string in getAllFilesLabels:
return id_string + ">>" + ', '.join([f.path for f in target.files.to_list()])
return id_string + ">>" + ', '.join(get_all_files(target))
elif id_string in getCcObjectFilesLabels:
return id_string + ">>" + ', '.join(get_cc_object_files(target))
elif id_string in getAllFilesAndCcObjectFilesLabels:
return id_string + ">>" + ', '.join(get_all_files(target)) + "|" + ', '.join(get_cc_object_files(target))
else:
# This target was not requested via cquery, and thus must be a dependency
# of a requested target.
@ -502,6 +549,7 @@ def format(target):
`
var getAllFilesDeps []string = nil
var getCcObjectFilesDeps []string = nil
var getAllFilesAndCcObjectFilesDeps []string = nil
for val, _ := range context.requests {
labelWithArch := getCqueryId(val)
@ -511,12 +559,16 @@ def format(target):
getAllFilesDeps = append(getAllFilesDeps, mapEntryString)
case getCcObjectFiles:
getCcObjectFilesDeps = append(getCcObjectFilesDeps, mapEntryString)
case getAllFilesAndCcObjectFiles:
getAllFilesAndCcObjectFilesDeps = append(getAllFilesAndCcObjectFilesDeps, mapEntryString)
}
}
getAllFilesDepsString := strings.Join(getAllFilesDeps, ",\n ")
getCcObjectFilesDepsString := strings.Join(getCcObjectFilesDeps, ",\n ")
getAllFilesAndCcObjectFilesDepsString := strings.Join(getAllFilesAndCcObjectFilesDeps, ",\n ")
return []byte(fmt.Sprintf(formatString, getAllFilesDepsString, getCcObjectFilesDepsString))
return []byte(fmt.Sprintf(formatString, getAllFilesDepsString, getCcObjectFilesDepsString,
getAllFilesAndCcObjectFilesDepsString))
}
// Returns a workspace-relative path containing build-related metadata required
@ -531,6 +583,7 @@ func (context *bazelContext) InvokeBazel() error {
context.results = make(map[cqueryKey]string)
var cqueryOutput string
var cqueryErr string
var err error
intermediatesDirPath := absolutePath(context.intermediatesDir())
@ -568,7 +621,7 @@ func (context *bazelContext) InvokeBazel() error {
return err
}
buildrootLabel := "//:buildroot"
cqueryOutput, err = context.issueBazelCommand(bazel.CqueryBuildRootRunName, "cquery",
cqueryOutput, cqueryErr, err = context.issueBazelCommand(bazel.CqueryBuildRootRunName, "cquery",
[]string{fmt.Sprintf("kind(rule, deps(%s))", buildrootLabel)},
"--output=starlark",
"--starlark:file="+cqueryFileRelpath)
@ -595,7 +648,8 @@ func (context *bazelContext) InvokeBazel() error {
if cqueryResult, ok := cqueryResults[getCqueryId(val)]; ok {
context.results[val] = string(cqueryResult)
} else {
return fmt.Errorf("missing result for bazel target %s. query output: [%s]", getCqueryId(val), cqueryOutput)
return fmt.Errorf("missing result for bazel target %s. query output: [%s], cquery err: [%s]",
getCqueryId(val), cqueryOutput, cqueryErr)
}
}
@ -603,7 +657,7 @@ func (context *bazelContext) InvokeBazel() error {
//
// TODO(cparsons): Use --target_pattern_file to avoid command line limits.
var aqueryOutput string
aqueryOutput, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery",
aqueryOutput, _, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery",
[]string{fmt.Sprintf("deps(%s)", buildrootLabel),
// Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
// proto sources, which would add a number of unnecessary dependencies.
@ -621,7 +675,7 @@ func (context *bazelContext) InvokeBazel() error {
// Issue a build command of the phony root to generate symlink forests for dependencies of the
// Bazel build. This is necessary because aquery invocations do not generate this symlink forest,
// but some of symlinks may be required to resolve source dependencies of the build.
_, err = context.issueBazelCommand(bazel.BazelBuildPhonyRootRunName, "build",
_, _, err = context.issueBazelCommand(bazel.BazelBuildPhonyRootRunName, "build",
[]string{"//:phonyroot"})
if err != nil {

View File

@ -230,6 +230,7 @@ func LibraryStaticFactory() android.Module {
module, library := NewLibrary(android.HostAndDeviceSupported)
library.BuildOnlyStatic()
module.sdkMemberTypes = []android.SdkMemberType{staticLibrarySdkMemberType}
module.bazelHandler = &staticLibraryBazelHandler{module: module}
return module.Init()
}
@ -406,6 +407,49 @@ type libraryDecorator struct {
collectedSnapshotHeaders android.Paths
}
type staticLibraryBazelHandler struct {
bazelHandler
module *Module
}
func (handler *staticLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext
outputPaths, objPaths, ok := bazelCtx.GetAllFilesAndCcObjectFiles(label, ctx.Arch().ArchType)
if ok {
if len(outputPaths) != 1 {
// TODO(cparsons): This is actually expected behavior for static libraries with no srcs.
// We should support this.
ctx.ModuleErrorf("expected exactly one output file for '%s', but got %s", label, objPaths)
return false
}
outputFilePath := android.PathForBazelOut(ctx, outputPaths[0])
handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
objFiles := make(android.Paths, len(objPaths))
for i, objPath := range objPaths {
objFiles[i] = android.PathForBazelOut(ctx, objPath)
}
objects := Objects{
objFiles: objFiles,
}
ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
StaticLibrary: outputFilePath,
ReuseObjects: objects,
Objects: objects,
// TODO(cparsons): Include transitive static libraries in this provider to support
// static libraries with deps.
TransitiveStaticLibrariesForOrdering: android.NewDepSetBuilder(android.TOPOLOGICAL).
Direct(outputFilePath).
Build(),
})
handler.module.outputFile = android.OptionalPathForPath(android.PathForBazelOut(ctx, objPaths[0]))
}
return ok
}
// collectHeadersForSnapshot collects all exported headers from library.
// It globs header files in the source tree for exported include directories,
// and tracks generated header files separately.