Merge "mixed builds for cc_static_library without deps"
This commit is contained in:
@@ -37,6 +37,7 @@ type CqueryRequestType int
|
|||||||
const (
|
const (
|
||||||
getAllFiles CqueryRequestType = iota
|
getAllFiles CqueryRequestType = iota
|
||||||
getCcObjectFiles
|
getCcObjectFiles
|
||||||
|
getAllFilesAndCcObjectFiles
|
||||||
)
|
)
|
||||||
|
|
||||||
// Map key to describe bazel cquery requests.
|
// Map key to describe bazel cquery requests.
|
||||||
@@ -58,7 +59,9 @@ type BazelContext interface {
|
|||||||
// Retrieves these files from Bazel's CcInfo provider.
|
// Retrieves these files from Bazel's CcInfo provider.
|
||||||
GetCcObjectFiles(label string, archType ArchType) ([]string, bool)
|
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
|
// ** End cquery methods
|
||||||
|
|
||||||
// Issues commands to Bazel to receive results for all cquery requests
|
// 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
|
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 {
|
func (m MockBazelContext) InvokeBazel() error {
|
||||||
panic("unimplemented")
|
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) {
|
func (n noopBazelContext) GetAllFiles(label string, archType ArchType) ([]string, bool) {
|
||||||
panic("unimplemented")
|
panic("unimplemented")
|
||||||
}
|
}
|
||||||
@@ -162,6 +186,10 @@ func (n noopBazelContext) GetCcObjectFiles(label string, archType ArchType) ([]s
|
|||||||
panic("unimplemented")
|
panic("unimplemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n noopBazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
func (n noopBazelContext) InvokeBazel() error {
|
func (n noopBazelContext) InvokeBazel() error {
|
||||||
panic("unimplemented")
|
panic("unimplemented")
|
||||||
}
|
}
|
||||||
@@ -253,8 +281,12 @@ func pwdPrefix() string {
|
|||||||
return ""
|
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,
|
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 := []string{"--output_base=" + context.outputBase, command}
|
||||||
cmdFlags = append(cmdFlags, labels...)
|
cmdFlags = append(cmdFlags, labels...)
|
||||||
@@ -281,9 +313,10 @@ func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command st
|
|||||||
bazelCmd.Stderr = stderr
|
bazelCmd.Stderr = stderr
|
||||||
|
|
||||||
if output, err := bazelCmd.Output(); err != nil {
|
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 {
|
} 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 ")))
|
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 {
|
func (context *bazelContext) cqueryStarlarkFileContents() []byte {
|
||||||
formatString := `
|
formatString := `
|
||||||
# This file is generated by soong_build. Do not edit.
|
# This file is generated by soong_build. Do not edit.
|
||||||
@@ -463,6 +501,13 @@ getCcObjectFilesLabels = {
|
|||||||
%s
|
%s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getAllFilesAndCcObjectFilesLabels = {
|
||||||
|
%s
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_all_files(target):
|
||||||
|
return [f.path for f in target.files.to_list()]
|
||||||
|
|
||||||
def get_cc_object_files(target):
|
def get_cc_object_files(target):
|
||||||
result = []
|
result = []
|
||||||
linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list()
|
linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list()
|
||||||
@@ -492,9 +537,11 @@ def get_arch(target):
|
|||||||
def format(target):
|
def format(target):
|
||||||
id_string = str(target.label) + "|" + get_arch(target)
|
id_string = str(target.label) + "|" + get_arch(target)
|
||||||
if id_string in getAllFilesLabels:
|
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:
|
elif id_string in getCcObjectFilesLabels:
|
||||||
return id_string + ">>" + ', '.join(get_cc_object_files(target))
|
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:
|
else:
|
||||||
# This target was not requested via cquery, and thus must be a dependency
|
# This target was not requested via cquery, and thus must be a dependency
|
||||||
# of a requested target.
|
# of a requested target.
|
||||||
@@ -502,6 +549,7 @@ def format(target):
|
|||||||
`
|
`
|
||||||
var getAllFilesDeps []string = nil
|
var getAllFilesDeps []string = nil
|
||||||
var getCcObjectFilesDeps []string = nil
|
var getCcObjectFilesDeps []string = nil
|
||||||
|
var getAllFilesAndCcObjectFilesDeps []string = nil
|
||||||
|
|
||||||
for val, _ := range context.requests {
|
for val, _ := range context.requests {
|
||||||
labelWithArch := getCqueryId(val)
|
labelWithArch := getCqueryId(val)
|
||||||
@@ -511,12 +559,16 @@ def format(target):
|
|||||||
getAllFilesDeps = append(getAllFilesDeps, mapEntryString)
|
getAllFilesDeps = append(getAllFilesDeps, mapEntryString)
|
||||||
case getCcObjectFiles:
|
case getCcObjectFiles:
|
||||||
getCcObjectFilesDeps = append(getCcObjectFilesDeps, mapEntryString)
|
getCcObjectFilesDeps = append(getCcObjectFilesDeps, mapEntryString)
|
||||||
|
case getAllFilesAndCcObjectFiles:
|
||||||
|
getAllFilesAndCcObjectFilesDeps = append(getAllFilesAndCcObjectFilesDeps, mapEntryString)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getAllFilesDepsString := strings.Join(getAllFilesDeps, ",\n ")
|
getAllFilesDepsString := strings.Join(getAllFilesDeps, ",\n ")
|
||||||
getCcObjectFilesDepsString := strings.Join(getCcObjectFilesDeps, ",\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
|
// 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)
|
context.results = make(map[cqueryKey]string)
|
||||||
|
|
||||||
var cqueryOutput string
|
var cqueryOutput string
|
||||||
|
var cqueryErr string
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
intermediatesDirPath := absolutePath(context.intermediatesDir())
|
intermediatesDirPath := absolutePath(context.intermediatesDir())
|
||||||
@@ -568,7 +621,7 @@ func (context *bazelContext) InvokeBazel() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buildrootLabel := "//:buildroot"
|
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)},
|
[]string{fmt.Sprintf("kind(rule, deps(%s))", buildrootLabel)},
|
||||||
"--output=starlark",
|
"--output=starlark",
|
||||||
"--starlark:file="+cqueryFileRelpath)
|
"--starlark:file="+cqueryFileRelpath)
|
||||||
@@ -595,7 +648,8 @@ func (context *bazelContext) InvokeBazel() error {
|
|||||||
if cqueryResult, ok := cqueryResults[getCqueryId(val)]; ok {
|
if cqueryResult, ok := cqueryResults[getCqueryId(val)]; ok {
|
||||||
context.results[val] = string(cqueryResult)
|
context.results[val] = string(cqueryResult)
|
||||||
} else {
|
} 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.
|
// TODO(cparsons): Use --target_pattern_file to avoid command line limits.
|
||||||
var aqueryOutput string
|
var aqueryOutput string
|
||||||
aqueryOutput, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery",
|
aqueryOutput, _, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery",
|
||||||
[]string{fmt.Sprintf("deps(%s)", buildrootLabel),
|
[]string{fmt.Sprintf("deps(%s)", buildrootLabel),
|
||||||
// Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
|
// 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.
|
// 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
|
// 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,
|
// 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.
|
// 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"})
|
[]string{"//:phonyroot"})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -230,6 +230,7 @@ func LibraryStaticFactory() android.Module {
|
|||||||
module, library := NewLibrary(android.HostAndDeviceSupported)
|
module, library := NewLibrary(android.HostAndDeviceSupported)
|
||||||
library.BuildOnlyStatic()
|
library.BuildOnlyStatic()
|
||||||
module.sdkMemberTypes = []android.SdkMemberType{staticLibrarySdkMemberType}
|
module.sdkMemberTypes = []android.SdkMemberType{staticLibrarySdkMemberType}
|
||||||
|
module.bazelHandler = &staticLibraryBazelHandler{module: module}
|
||||||
return module.Init()
|
return module.Init()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,6 +407,49 @@ type libraryDecorator struct {
|
|||||||
collectedSnapshotHeaders android.Paths
|
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.
|
// collectHeadersForSnapshot collects all exported headers from library.
|
||||||
// It globs header files in the source tree for exported include directories,
|
// It globs header files in the source tree for exported include directories,
|
||||||
// and tracks generated header files separately.
|
// and tracks generated header files separately.
|
||||||
|
Reference in New Issue
Block a user