Merge "Add OS to configuration key in mixed builds"

This commit is contained in:
Christopher Parsons
2021-10-19 20:57:47 +00:00
committed by Gerrit Code Review
8 changed files with 79 additions and 61 deletions

View File

@@ -48,11 +48,17 @@ type cqueryRequest interface {
StarlarkFunctionBody() string StarlarkFunctionBody() string
} }
// Portion of cquery map key to describe target configuration.
type configKey struct {
archType ArchType
osType OsType
}
// Map key to describe bazel cquery requests. // Map key to describe bazel cquery requests.
type cqueryKey struct { type cqueryKey struct {
label string label string
requestType cqueryRequest requestType cqueryRequest
archType ArchType configKey configKey
} }
// bazelHandler is the interface for a helper object related to deferring to Bazel for // bazelHandler is the interface for a helper object related to deferring to Bazel for
@@ -72,14 +78,14 @@ type BazelContext interface {
// has been queued to be run later. // has been queued to be run later.
// Returns result files built by building the given bazel target label. // Returns result files built by building the given bazel target label.
GetOutputFiles(label string, archType ArchType) ([]string, bool) GetOutputFiles(label string, cfgKey configKey) ([]string, bool)
// TODO(cparsons): Other cquery-related methods should be added here. // TODO(cparsons): Other cquery-related methods should be added here.
// Returns the results of GetOutputFiles and GetCcObjectFiles in a single query (in that order). // Returns the results of GetOutputFiles and GetCcObjectFiles in a single query (in that order).
GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) GetCcInfo(label string, cfgKey configKey) (cquery.CcInfo, bool, error)
// Returns the executable binary resultant from building together the python sources // Returns the executable binary resultant from building together the python sources
GetPythonBinary(label string, archType ArchType) (string, bool) GetPythonBinary(label string, cfgKey configKey) (string, bool)
// ** End cquery methods // ** End cquery methods
@@ -140,17 +146,17 @@ type MockBazelContext struct {
LabelToPythonBinary map[string]string LabelToPythonBinary map[string]string
} }
func (m MockBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) { func (m MockBazelContext) GetOutputFiles(label string, cfgKey configKey) ([]string, bool) {
result, ok := m.LabelToOutputFiles[label] result, ok := m.LabelToOutputFiles[label]
return result, ok return result, ok
} }
func (m MockBazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) { func (m MockBazelContext) GetCcInfo(label string, cfgKey configKey) (cquery.CcInfo, bool, error) {
result, ok := m.LabelToCcInfo[label] result, ok := m.LabelToCcInfo[label]
return result, ok, nil return result, ok, nil
} }
func (m MockBazelContext) GetPythonBinary(label string, archType ArchType) (string, bool) { func (m MockBazelContext) GetPythonBinary(label string, cfgKey configKey) (string, bool) {
result, ok := m.LabelToPythonBinary[label] result, ok := m.LabelToPythonBinary[label]
return result, ok return result, ok
} }
@@ -171,8 +177,8 @@ func (m MockBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
var _ BazelContext = MockBazelContext{} var _ BazelContext = MockBazelContext{}
func (bazelCtx *bazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) { func (bazelCtx *bazelContext) GetOutputFiles(label string, cfgKey configKey) ([]string, bool) {
rawString, ok := bazelCtx.cquery(label, cquery.GetOutputFiles, archType) rawString, ok := bazelCtx.cquery(label, cquery.GetOutputFiles, cfgKey)
var ret []string var ret []string
if ok { if ok {
bazelOutput := strings.TrimSpace(rawString) bazelOutput := strings.TrimSpace(rawString)
@@ -181,8 +187,8 @@ func (bazelCtx *bazelContext) GetOutputFiles(label string, archType ArchType) ([
return ret, ok return ret, ok
} }
func (bazelCtx *bazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) { func (bazelCtx *bazelContext) GetCcInfo(label string, cfgKey configKey) (cquery.CcInfo, bool, error) {
result, ok := bazelCtx.cquery(label, cquery.GetCcInfo, archType) result, ok := bazelCtx.cquery(label, cquery.GetCcInfo, cfgKey)
if !ok { if !ok {
return cquery.CcInfo{}, ok, nil return cquery.CcInfo{}, ok, nil
} }
@@ -192,8 +198,8 @@ func (bazelCtx *bazelContext) GetCcInfo(label string, archType ArchType) (cquery
return ret, ok, err return ret, ok, err
} }
func (bazelCtx *bazelContext) GetPythonBinary(label string, archType ArchType) (string, bool) { func (bazelCtx *bazelContext) GetPythonBinary(label string, cfgKey configKey) (string, bool) {
rawString, ok := bazelCtx.cquery(label, cquery.GetPythonBinary, archType) rawString, ok := bazelCtx.cquery(label, cquery.GetPythonBinary, cfgKey)
var ret string var ret string
if ok { if ok {
bazelOutput := strings.TrimSpace(rawString) bazelOutput := strings.TrimSpace(rawString)
@@ -202,15 +208,15 @@ func (bazelCtx *bazelContext) GetPythonBinary(label string, archType ArchType) (
return ret, ok return ret, ok
} }
func (n noopBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) { func (n noopBazelContext) GetOutputFiles(label string, cfgKey configKey) ([]string, bool) {
panic("unimplemented") panic("unimplemented")
} }
func (n noopBazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) { func (n noopBazelContext) GetCcInfo(label string, cfgKey configKey) (cquery.CcInfo, bool, error) {
panic("unimplemented") panic("unimplemented")
} }
func (n noopBazelContext) GetPythonBinary(label string, archType ArchType) (string, bool) { func (n noopBazelContext) GetPythonBinary(label string, cfgKey configKey) (string, bool) {
panic("unimplemented") panic("unimplemented")
} }
@@ -303,8 +309,8 @@ func (context *bazelContext) BazelEnabled() bool {
// returns (result, true). If the request is queued but no results are available, // returns (result, true). If the request is queued but no results are available,
// then returns ("", false). // then returns ("", false).
func (context *bazelContext) cquery(label string, requestType cqueryRequest, func (context *bazelContext) cquery(label string, requestType cqueryRequest,
archType ArchType) (string, bool) { cfgKey configKey) (string, bool) {
key := cqueryKey{label, requestType, archType} key := cqueryKey{label, requestType, cfgKey}
if result, ok := context.results[key]; ok { if result, ok := context.results[key]; ok {
return result, true return result, true
} else { } else {
@@ -419,7 +425,7 @@ func (context *bazelContext) mainBzlFileContents() []byte {
def _config_node_transition_impl(settings, attr): def _config_node_transition_impl(settings, attr):
return { return {
"//command_line_option:platforms": "@//build/bazel/platforms:android_%s" % attr.arch, "//command_line_option:platforms": "@//build/bazel/platforms:%s_%s" % (attr.os, attr.arch),
} }
_config_node_transition = transition( _config_node_transition = transition(
@@ -437,7 +443,8 @@ config_node = rule(
implementation = _passthrough_rule_impl, implementation = _passthrough_rule_impl,
attrs = { attrs = {
"arch" : attr.string(mandatory = True), "arch" : attr.string(mandatory = True),
"deps" : attr.label_list(cfg = _config_node_transition), "os" : attr.string(mandatory = True),
"deps" : attr.label_list(cfg = _config_node_transition, allow_files = True),
"_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"),
}, },
) )
@@ -488,38 +495,32 @@ phony_root(name = "phonyroot",
configNodeFormatString := ` configNodeFormatString := `
config_node(name = "%s", config_node(name = "%s",
arch = "%s", arch = "%s",
os = "%s",
deps = [%s], deps = [%s],
) )
`
commonArchFilegroupString := `
filegroup(name = "common",
srcs = [%s],
)
` `
configNodesSection := "" configNodesSection := ""
labelsByArch := map[string][]string{} labelsByConfig := map[string][]string{}
for val, _ := range context.requests { for val, _ := range context.requests {
labelString := fmt.Sprintf("\"@%s\"", val.label) labelString := fmt.Sprintf("\"@%s\"", val.label)
archString := getArchString(val) configString := getConfigString(val)
labelsByArch[archString] = append(labelsByArch[archString], labelString) labelsByConfig[configString] = append(labelsByConfig[configString], labelString)
} }
allLabels := []string{} allLabels := []string{}
for archString, labels := range labelsByArch { for configString, labels := range labelsByConfig {
if archString == "common" { configTokens := strings.Split(configString, "|")
// arch-less labels (e.g. filegroups) don't need a config_node if len(configTokens) != 2 {
allLabels = append(allLabels, "\":common\"") panic(fmt.Errorf("Unexpected config string format: %s", configString))
labelsString := strings.Join(labels, ",\n ")
configNodesSection += fmt.Sprintf(commonArchFilegroupString, labelsString)
} else {
// Create a config_node, and add the config_node's label to allLabels
allLabels = append(allLabels, fmt.Sprintf("\":%s\"", archString))
labelsString := strings.Join(labels, ",\n ")
configNodesSection += fmt.Sprintf(configNodeFormatString, archString, archString, labelsString)
} }
archString := configTokens[0]
osString := configTokens[1]
targetString := fmt.Sprintf("%s_%s", osString, archString)
allLabels = append(allLabels, fmt.Sprintf("\":%s\"", targetString))
labelsString := strings.Join(labels, ",\n ")
configNodesSection += fmt.Sprintf(configNodeFormatString, targetString, archString, osString, labelsString)
} }
return []byte(fmt.Sprintf(formatString, configNodesSection, strings.Join(allLabels, ",\n "))) return []byte(fmt.Sprintf(formatString, configNodesSection, strings.Join(allLabels, ",\n ")))
@@ -587,11 +588,15 @@ def %s(target):
%s %s
def get_arch(target): def get_arch(target):
# TODO(b/199363072): filegroups and file targets aren't associated with any
# specific platform architecture in mixed builds. This is consistent with how
# Soong treats filegroups, but it may not be the case with manually-written
# filegroup BUILD targets.
buildoptions = build_options(target) buildoptions = build_options(target)
if buildoptions == None: if buildoptions == None:
# File targets do not have buildoptions. File targets aren't associated with # File targets do not have buildoptions. File targets aren't associated with
# any specific platform architecture in mixed builds. # any specific platform architecture in mixed builds, so use the host.
return "common" return "x86_64|linux"
platforms = build_options(target)["//command_line_option:platforms"] platforms = build_options(target)["//command_line_option:platforms"]
if len(platforms) != 1: if len(platforms) != 1:
# An individual configured target should have only one platform architecture. # An individual configured target should have only one platform architecture.
@@ -601,10 +606,12 @@ def get_arch(target):
platform_name = build_options(target)["//command_line_option:platforms"][0].name platform_name = build_options(target)["//command_line_option:platforms"][0].name
if platform_name == "host": if platform_name == "host":
return "HOST" return "HOST"
elif platform_name.startswith("linux_glibc_"):
return platform_name[len("linux_glibc_"):] + "|" + platform_name[:len("linux_glibc_")-1]
elif platform_name.startswith("android_"): elif platform_name.startswith("android_"):
return platform_name[len("android_"):] return platform_name[len("android_"):] + "|" + platform_name[:len("android_")-1]
elif platform_name.startswith("linux_"): elif platform_name.startswith("linux_"):
return platform_name[len("linux_"):] return platform_name[len("linux_"):] + "|" + platform_name[:len("linux_")-1]
else: else:
fail("expected platform name of the form 'android_<arch>' or 'linux_<arch>', but was " + str(platforms)) fail("expected platform name of the form 'android_<arch>' or 'linux_<arch>', but was " + str(platforms))
return "UNKNOWN" return "UNKNOWN"
@@ -852,14 +859,23 @@ func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) {
} }
func getCqueryId(key cqueryKey) string { func getCqueryId(key cqueryKey) string {
return key.label + "|" + getArchString(key) return key.label + "|" + getConfigString(key)
} }
func getArchString(key cqueryKey) string { func getConfigString(key cqueryKey) string {
arch := key.archType.Name arch := key.configKey.archType.Name
if len(arch) > 0 { if len(arch) == 0 || arch == "common" {
return arch // Use host platform, which is currently hardcoded to be x86_64.
} else { arch = "x86_64"
return "x86_64"
} }
os := key.configKey.osType.Name
if len(os) == 0 || os == "common_os" {
// Use host OS, which is currently hardcoded to be linux.
os = "linux"
}
return arch + "|" + os
}
func GetConfigKey(ctx ModuleContext) configKey {
return configKey{archType: ctx.Arch().ArchType, osType: ctx.Os()}
} }

View File

@@ -9,11 +9,11 @@ import (
func TestRequestResultsAfterInvokeBazel(t *testing.T) { func TestRequestResultsAfterInvokeBazel(t *testing.T) {
label := "//foo:bar" label := "//foo:bar"
arch := Arm64 cfg := configKey{Arm64, Android}
bazelContext, _ := testBazelContext(t, map[bazelCommand]string{ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: `//foo:bar|arm64>>out/foo/bar.txt`, bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: `//foo:bar|arm64|android>>out/foo/bar.txt`,
}) })
g, ok := bazelContext.GetOutputFiles(label, arch) g, ok := bazelContext.GetOutputFiles(label, cfg)
if ok { if ok {
t.Errorf("Did not expect cquery results prior to running InvokeBazel(), but got %s", g) t.Errorf("Did not expect cquery results prior to running InvokeBazel(), but got %s", g)
} }
@@ -21,7 +21,7 @@ func TestRequestResultsAfterInvokeBazel(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Did not expect error invoking Bazel, but got %s", err) t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
} }
g, ok = bazelContext.GetOutputFiles(label, arch) g, ok = bazelContext.GetOutputFiles(label, cfg)
if !ok { if !ok {
t.Errorf("Expected cquery results after running InvokeBazel(), but got none") t.Errorf("Expected cquery results after running InvokeBazel(), but got none")
} else if w := []string{"out/foo/bar.txt"}; !reflect.DeepEqual(w, g) { } else if w := []string{"out/foo/bar.txt"}; !reflect.DeepEqual(w, g) {

View File

@@ -118,14 +118,16 @@ func (fg *fileGroup) maybeGenerateBazelBuildActions(ctx ModuleContext) {
} }
archVariant := ctx.Arch().ArchType archVariant := ctx.Arch().ArchType
osVariant := ctx.Os()
if len(fg.Srcs()) == 1 && fg.Srcs()[0].Base() == fg.Name() { if len(fg.Srcs()) == 1 && fg.Srcs()[0].Base() == fg.Name() {
// This will be a regular file target, not filegroup, in Bazel. // This will be a regular file target, not filegroup, in Bazel.
// See FilegroupBp2Build for more information. // See FilegroupBp2Build for more information.
archVariant = Common archVariant = Common
osVariant = CommonOS
} }
bazelCtx := ctx.Config().BazelContext bazelCtx := ctx.Config().BazelContext
filePaths, ok := bazelCtx.GetOutputFiles(fg.GetBazelLabel(ctx, fg), archVariant) filePaths, ok := bazelCtx.GetOutputFiles(fg.GetBazelLabel(ctx, fg), configKey{archVariant, osVariant})
if !ok { if !ok {
return return
} }

View File

@@ -639,7 +639,7 @@ func (handler *ccLibraryBazelHandler) generateSharedBazelBuildActions(ctx androi
func (handler *ccLibraryBazelHandler) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool { func (handler *ccLibraryBazelHandler) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext bazelCtx := ctx.Config().BazelContext
ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType) ccInfo, ok, err := bazelCtx.GetCcInfo(label, android.GetConfigKey(ctx))
if err != nil { if err != nil {
ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err) ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err)
return false return false

View File

@@ -57,7 +57,7 @@ type libraryHeaderBazelHander struct {
func (h *libraryHeaderBazelHander) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool { func (h *libraryHeaderBazelHander) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext bazelCtx := ctx.Config().BazelContext
ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType) ccInfo, ok, err := bazelCtx.GetCcInfo(label, android.GetConfigKey(ctx))
if err != nil { if err != nil {
ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err) ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err)
return false return false

View File

@@ -54,7 +54,7 @@ type objectBazelHandler struct {
func (handler *objectBazelHandler) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool { func (handler *objectBazelHandler) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext bazelCtx := ctx.Config().BazelContext
objPaths, ok := bazelCtx.GetOutputFiles(label, ctx.Arch().ArchType) objPaths, ok := bazelCtx.GetOutputFiles(label, android.GetConfigKey(ctx))
if ok { if ok {
if len(objPaths) != 1 { if len(objPaths) != 1 {
ctx.ModuleErrorf("expected exactly one object file for '%s', but got %s", label, objPaths) ctx.ModuleErrorf("expected exactly one object file for '%s', but got %s", label, objPaths)

View File

@@ -330,7 +330,7 @@ type prebuiltStaticLibraryBazelHandler struct {
func (h *prebuiltStaticLibraryBazelHandler) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool { func (h *prebuiltStaticLibraryBazelHandler) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext bazelCtx := ctx.Config().BazelContext
ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType) ccInfo, ok, err := bazelCtx.GetCcInfo(label, android.GetConfigKey(ctx))
if err != nil { if err != nil {
ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err) ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err)
} }

View File

@@ -248,7 +248,7 @@ func toolDepsMutator(ctx android.BottomUpMutatorContext) {
// Returns true if information was available from Bazel, false if bazel invocation still needs to occur. // Returns true if information was available from Bazel, false if bazel invocation still needs to occur.
func (c *Module) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool { func (c *Module) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext bazelCtx := ctx.Config().BazelContext
filePaths, ok := bazelCtx.GetOutputFiles(label, ctx.Arch().ArchType) filePaths, ok := bazelCtx.GetOutputFiles(label, android.GetConfigKey(ctx))
if ok { if ok {
var bazelOutputFiles android.Paths var bazelOutputFiles android.Paths
exportIncludeDirs := map[string]bool{} exportIncludeDirs := map[string]bool{}