Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 944e7d01 authored by Chris Parsons's avatar Chris Parsons
Browse files

Refactor and cleanup of cquery processing

Test: USE_BAZEL_ANALYSIS=1 m libc
Change-Id: Iaf9a92e84d39c132e2444a8aaafd79505a12b8ec
parent 2bed9ffa
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ bootstrap_go_package {
        "soong",
        "soong-android-soongconfig",
        "soong-bazel",
        "soong-cquery",
        "soong-shared",
        "soong-ui-metrics_proto",
    ],
+85 −79
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import (
	"strings"
	"sync"

	"android/soong/bazel/cquery"
	"github.com/google/blueprint/bootstrap"

	"android/soong/bazel"
@@ -43,7 +44,7 @@ const (
// Map key to describe bazel cquery requests.
type cqueryKey struct {
	label       string
	requestType CqueryRequestType
	requestType cquery.RequestType
	archType    ArchType
}

@@ -53,14 +54,15 @@ type BazelContext interface {
	// has been queued to be run later.

	// Returns result files built by building the given bazel target label.
	GetAllFiles(label string, archType ArchType) ([]string, bool)
	GetOutputFiles(label string, archType ArchType) ([]string, bool)

	// Returns object files produced by compiling the given cc-related target.
	// Retrieves these files from Bazel's CcInfo provider.
	GetCcObjectFiles(label string, archType ArchType) ([]string, bool)

	// Returns the results of GetAllFiles and GetCcObjectFiles in a single query (in that order).
	GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool)
	// TODO(cparsons): Other cquery-related methods should be added here.
	// Returns the results of GetOutputFiles and GetCcObjectFiles in a single query (in that order).
	GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool)

	// ** End cquery methods

@@ -109,7 +111,7 @@ type MockBazelContext struct {
	AllFiles map[string][]string
}

func (m MockBazelContext) GetAllFiles(label string, archType ArchType) ([]string, bool) {
func (m MockBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
	result, ok := m.AllFiles[label]
	return result, ok
}
@@ -119,7 +121,7 @@ func (m MockBazelContext) GetCcObjectFiles(label string, archType ArchType) ([]s
	return result, ok
}

func (m MockBazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
func (m MockBazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
	result, ok := m.AllFiles[label]
	return result, result, ok
}
@@ -142,43 +144,42 @@ func (m MockBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {

var _ BazelContext = MockBazelContext{}

func (bazelCtx *bazelContext) GetAllFiles(label string, archType ArchType) ([]string, bool) {
	result, ok := bazelCtx.cquery(label, getAllFiles, archType)
func (bazelCtx *bazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
	rawString, ok := bazelCtx.cquery(label, cquery.GetOutputFiles, archType)
	var ret []string
	if ok {
		bazelOutput := strings.TrimSpace(result)
		return strings.Split(bazelOutput, ", "), true
	} else {
		return nil, false
		bazelOutput := strings.TrimSpace(rawString)
		ret = cquery.GetOutputFiles.ParseResult(bazelOutput).([]string)
	}
	return ret, ok
}

func (bazelCtx *bazelContext) GetCcObjectFiles(label string, archType ArchType) ([]string, bool) {
	result, ok := bazelCtx.cquery(label, getCcObjectFiles, archType)
	rawString, ok := bazelCtx.cquery(label, cquery.GetCcObjectFiles, archType)
	var returnResult []string
	if ok {
		bazelOutput := strings.TrimSpace(result)
		return strings.Split(bazelOutput, ", "), true
	} else {
		return nil, false
		bazelOutput := strings.TrimSpace(rawString)
		returnResult = cquery.GetCcObjectFiles.ParseResult(bazelOutput).([]string)
	}
	return returnResult, ok
}

func (bazelCtx *bazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
	var allFiles []string
func (bazelCtx *bazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
	var outputFiles []string
	var ccObjects []string

	result, ok := bazelCtx.cquery(label, getAllFilesAndCcObjectFiles, archType)
	result, ok := bazelCtx.cquery(label, cquery.GetOutputFilesAndCcObjectFiles, 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, ", ")
		returnResult := cquery.GetOutputFilesAndCcObjectFiles.ParseResult(bazelOutput).(cquery.GetOutputFilesAndCcObjectFiles_Result)
		outputFiles = returnResult.OutputFiles
		ccObjects = returnResult.CcObjectFiles
	}
	return allFiles, ccObjects, ok

	return outputFiles, ccObjects, ok
}

func (n noopBazelContext) GetAllFiles(label string, archType ArchType) ([]string, bool) {
func (n noopBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
	panic("unimplemented")
}

@@ -186,7 +187,7 @@ func (n noopBazelContext) GetCcObjectFiles(label string, archType ArchType) ([]s
	panic("unimplemented")
}

func (n noopBazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
func (n noopBazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
	panic("unimplemented")
}

@@ -260,7 +261,7 @@ func (context *bazelContext) BazelEnabled() bool {
// If the given request was already made (and the results are available), then
// returns (result, true). If the request is queued but no results are available,
// then returns ("", false).
func (context *bazelContext) cquery(label string, requestType CqueryRequestType,
func (context *bazelContext) cquery(label string, requestType cquery.RequestType,
	archType ArchType) (string, bool) {
	key := cqueryKey{label, requestType, archType}
	if result, ok := context.results[key]; ok {
@@ -485,38 +486,66 @@ phony_root(name = "phonyroot",
		strings.Join(deps_arm, ",\n            ")))
}

func indent(original string) string {
	result := ""
	for _, line := range strings.Split(original, "\n") {
		result += "  " + line + "\n"
	}
	return result
}

// 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.
getAllFilesLabels = {
  %s
	requestTypeToCqueryIdEntries := map[cquery.RequestType][]string{}
	for val, _ := range context.requests {
		cqueryId := getCqueryId(val)
		mapEntryString := fmt.Sprintf("%q : True", cqueryId)
		requestTypeToCqueryIdEntries[val.requestType] =
			append(requestTypeToCqueryIdEntries[val.requestType], mapEntryString)
	}
	labelRegistrationMapSection := ""
	functionDefSection := ""
	mainSwitchSection := ""

getCcObjectFilesLabels = {
	mapDeclarationFormatString := `
%s = {
  %s
}

getAllFilesAndCcObjectFilesLabels = {
`
	functionDefFormatString := `
def %s(target):
%s
`
	mainSwitchSectionFormatString := `
  if id_string in %s:
    return id_string + ">>" + %s(target)
`

	for _, requestType := range cquery.RequestTypes {
		labelMapName := requestType.Name() + "_Labels"
		functionName := requestType.Name() + "_Fn"
		labelRegistrationMapSection += fmt.Sprintf(mapDeclarationFormatString,
			labelMapName,
			strings.Join(requestTypeToCqueryIdEntries[requestType], ",\n  "))
		functionDefSection += fmt.Sprintf(functionDefFormatString,
			functionName,
			indent(requestType.StarlarkFunctionBody()))
		mainSwitchSection += fmt.Sprintf(mainSwitchSectionFormatString,
			labelMapName, functionName)
	}

def get_all_files(target):
  return [f.path for f in target.files.to_list()]
	formatString := `
# This file is generated by soong_build. Do not edit.

def get_cc_object_files(target):
  result = []
  linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list()
# Label Map Section
%s

  for linker_input in linker_inputs:
    for library in linker_input.libraries:
      for object in library.objects:
        result += [object.path]
  return result
# Function Def Section
%s

def get_arch(target):
  buildoptions = build_options(target)
@@ -536,39 +565,16 @@ def get_arch(target):

def format(target):
  id_string = str(target.label) + "|" + get_arch(target)
  if id_string in getAllFilesLabels:
    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:

  # Main switch section
  %s
  # This target was not requested via cquery, and thus must be a dependency
  # of a requested target.
  return id_string + ">>NONE"
`
	var getAllFilesDeps []string = nil
	var getCcObjectFilesDeps []string = nil
	var getAllFilesAndCcObjectFilesDeps []string = nil

	for val, _ := range context.requests {
		labelWithArch := getCqueryId(val)
		mapEntryString := fmt.Sprintf("%q : True", labelWithArch)
		switch val.requestType {
		case getAllFiles:
			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,
		getAllFilesAndCcObjectFilesDepsString))
	return []byte(fmt.Sprintf(formatString, labelRegistrationMapSection, functionDefSection,
		mainSwitchSection))
}

// Returns a workspace-relative path containing build-related metadata required
+14 −0
Original line number Diff line number Diff line
package {
    default_applicable_licenses: ["Android-Apache-2.0"],
}

bootstrap_go_package {
    name: "soong-cquery",
    pkgPath: "android/soong/bazel/cquery",
    srcs: [
        "request_type.go",
    ],
    pluginFor: [
        "soong_build",
    ],
}
+110 −0
Original line number Diff line number Diff line
package cquery

import (
	"strings"
)

var (
	GetOutputFiles                 RequestType = &getOutputFilesRequestType{}
	GetCcObjectFiles               RequestType = &getCcObjectFilesRequestType{}
	GetOutputFilesAndCcObjectFiles RequestType = &getOutputFilesAndCcObjectFilesType{}
)

type GetOutputFilesAndCcObjectFiles_Result struct {
	OutputFiles   []string
	CcObjectFiles []string
}

var RequestTypes []RequestType = []RequestType{
	GetOutputFiles, GetCcObjectFiles, GetOutputFilesAndCcObjectFiles}

type RequestType interface {
	// Name returns a string name for this request type. Such request type names must be unique,
	// and must only consist of alphanumeric characters.
	Name() string

	// StarlarkFunctionBody returns a straark function body to process this request type.
	// The returned string is the body of a Starlark function which obtains
	// all request-relevant information about a target and returns a string containing
	// this information.
	// The function should have the following properties:
	//   - `target` is the only parameter to this function (a configured target).
	//   - The return value must be a string.
	//   - The function body should not be indented outside of its own scope.
	StarlarkFunctionBody() string

	// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
	// The given rawString must correspond to the string output which was created by evaluating the
	// Starlark given in StarlarkFunctionBody.
	// The type of this value depends on the request type; it is up to the caller to
	// cast to the correct type.
	ParseResult(rawString string) interface{}
}

type getOutputFilesRequestType struct{}

func (g getOutputFilesRequestType) Name() string {
	return "getOutputFiles"
}

func (g getOutputFilesRequestType) StarlarkFunctionBody() string {
	return "return ', '.join([f.path for f in target.files.to_list()])"
}

func (g getOutputFilesRequestType) ParseResult(rawString string) interface{} {
	return strings.Split(rawString, ", ")
}

type getCcObjectFilesRequestType struct{}

func (g getCcObjectFilesRequestType) Name() string {
	return "getCcObjectFiles"
}

func (g getCcObjectFilesRequestType) StarlarkFunctionBody() string {
	return `
result = []
linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list()

for linker_input in linker_inputs:
  for library in linker_input.libraries:
    for object in library.objects:
      result += [object.path]
return ', '.join(result)`
}

func (g getCcObjectFilesRequestType) ParseResult(rawString string) interface{} {
	return strings.Split(rawString, ", ")
}

type getOutputFilesAndCcObjectFilesType struct{}

func (g getOutputFilesAndCcObjectFilesType) Name() string {
	return "getOutputFilesAndCcObjectFiles"
}

func (g getOutputFilesAndCcObjectFilesType) StarlarkFunctionBody() string {
	return `
outputFiles = [f.path for f in target.files.to_list()]

ccObjectFiles = []
linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list()

for linker_input in linker_inputs:
  for library in linker_input.libraries:
    for object in library.objects:
      ccObjectFiles += [object.path]
return ', '.join(outputFiles) + "|" + ', '.join(ccObjectFiles)`
}

func (g getOutputFilesAndCcObjectFilesType) ParseResult(rawString string) interface{} {
	var outputFiles []string
	var ccObjects []string

	splitString := strings.Split(rawString, "|")
	outputFilesString := splitString[0]
	ccObjectsString := splitString[1]
	outputFiles = strings.Split(outputFilesString, ", ")
	ccObjects = strings.Split(ccObjectsString, ", ")
	return GetOutputFilesAndCcObjectFiles_Result{outputFiles, ccObjects}
}
+30 −29
Original line number Diff line number Diff line
@@ -415,8 +415,10 @@ type staticLibraryBazelHandler struct {

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 {
	outputPaths, objPaths, ok := bazelCtx.GetOutputFilesAndCcObjectFiles(label, ctx.Arch().ArchType)
	if !ok {
		return ok
	}
	if len(outputPaths) != 1 {
		// TODO(cparsons): This is actually expected behavior for static libraries with no srcs.
		// We should support this.
@@ -446,7 +448,6 @@ func (handler *staticLibraryBazelHandler) generateBazelBuildActions(ctx android.
			Build(),
	})
	handler.module.outputFile = android.OptionalPathForPath(android.PathForBazelOut(ctx, objPaths[0]))
	}
	return ok
}

Loading