Merge changes I8ca452aa,I437fc890,If9446700 into main

* changes:
  Handle .proto files in different package for filegroups
  Handle .proto files that end up in a different package
  Allow creation of BazelTargets in a different directory
This commit is contained in:
Spandan Das
2023-08-08 00:51:52 +00:00
committed by Gerrit Code Review
10 changed files with 315 additions and 48 deletions

View File

@@ -24,6 +24,7 @@ import (
"android/soong/ui/metrics/bp2build_metrics_proto"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
func init() {
@@ -141,8 +142,14 @@ func (fg *fileGroup) ConvertWithBp2build(ctx TopDownMutatorContext) {
attrs)
} else {
if fg.ShouldConvertToProtoLibrary(ctx) {
pkgToSrcs := partitionSrcsByPackage(ctx.ModuleDir(), bazel.MakeLabelList(srcs.Value.Includes))
if len(pkgToSrcs) > 1 {
ctx.ModuleErrorf("TODO: Add bp2build support for multiple package .protosrcs in filegroup")
return
}
pkg := SortedKeys(pkgToSrcs)[0]
attrs := &ProtoAttrs{
Srcs: srcs,
Srcs: bazel.MakeLabelListAttribute(pkgToSrcs[pkg]),
Strip_import_prefix: fg.properties.Path,
}
@@ -151,13 +158,39 @@ func (fg *fileGroup) ConvertWithBp2build(ctx TopDownMutatorContext) {
// TODO(b/246997908): we can remove this tag if we could figure out a solution for this bug.
"manual",
}
if pkg != ctx.ModuleDir() {
// Since we are creating the proto_library in a subpackage, create an import_prefix relative to the current package
if rel, err := filepath.Rel(ctx.ModuleDir(), pkg); err != nil {
ctx.ModuleErrorf("Could not get relative path for %v %v", pkg, err)
} else if rel != "." {
attrs.Import_prefix = &rel
// Strip the package prefix
attrs.Strip_import_prefix = proptools.StringPtr("")
}
}
ctx.CreateBazelTargetModule(
bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
CommonAttributes{
Name: fg.Name() + convertedProtoLibrarySuffix,
Name: fg.Name() + "_proto",
Dir: proptools.StringPtr(pkg),
Tags: bazel.MakeStringListAttribute(tags),
},
attrs)
// Create an alias in the current dir. The actual target might exist in a different package, but rdeps
// can reliabily use this alias
ctx.CreateBazelTargetModule(
bazel.BazelTargetModuleProperties{Rule_class: "alias"},
CommonAttributes{
Name: fg.Name() + convertedProtoLibrarySuffix,
// TODO(b/246997908): we can remove this tag if we could figure out a solution for this bug.
Tags: bazel.MakeStringListAttribute(tags),
},
&bazelAliasAttributes{
Actual: bazel.MakeLabelAttribute("//" + pkg + ":" + fg.Name() + "_proto"),
},
)
}
// TODO(b/242847534): Still convert to a filegroup because other unconverted

View File

@@ -1021,6 +1021,11 @@ type CommonAttributes struct {
Applicable_licenses bazel.LabelListAttribute
Testonly *bool
// Dir is neither a Soong nor Bazel target attribute
// If set, the bazel target will be created in this directory
// If unset, the bazel target will default to be created in the directory of the visited soong module
Dir *string
}
// constraintAttributes represents Bazel attributes pertaining to build constraints,

View File

@@ -17,6 +17,7 @@ package android
import (
"android/soong/bazel"
"android/soong/ui/metrics/bp2build_metrics_proto"
"path/filepath"
"github.com/google/blueprint"
)
@@ -757,6 +758,27 @@ func (t *topDownMutatorContext) CreateBazelTargetAliasInDir(
mod.base().addBp2buildInfo(info)
}
// Returns the directory in which the bazel target will be generated
// If ca.Dir is not nil, use that
// Otherwise default to the directory of the soong module
func dirForBazelTargetGeneration(t *topDownMutatorContext, ca *CommonAttributes) string {
dir := t.OtherModuleDir(t.Module())
if ca.Dir != nil {
dir = *ca.Dir
// Restrict its use to dirs that contain an Android.bp file.
// There are several places in bp2build where we use the existence of Android.bp/BUILD on the filesystem
// to curate a compatible label for src files (e.g. headers for cc).
// If we arbritrarily create BUILD files, then it might render those curated labels incompatible.
if exists, _, _ := t.Config().fs.Exists(filepath.Join(dir, "Android.bp")); !exists {
t.ModuleErrorf("Cannot use ca.Dir to create a BazelTarget in dir: %v since it does not contain an Android.bp file", dir)
}
// Set ca.Dir to nil so that it does not get emitted to the BUILD files
ca.Dir = nil
}
return dir
}
func (t *topDownMutatorContext) CreateBazelConfigSetting(
csa bazel.ConfigSettingAttributes,
ca CommonAttributes,
@@ -851,7 +873,7 @@ func (t *topDownMutatorContext) createBazelTargetModule(
constraintAttributes := commonAttrs.fillCommonBp2BuildModuleAttrs(t, enabledProperty)
mod := t.Module()
info := bp2buildInfo{
Dir: t.OtherModuleDir(mod),
Dir: dirForBazelTargetGeneration(t, &commonAttrs),
BazelProps: bazelProps,
CommonAttrs: commonAttrs,
ConstraintAttrs: constraintAttributes,

View File

@@ -15,6 +15,7 @@
package android
import (
"path/filepath"
"strings"
"android/soong/bazel"
@@ -156,12 +157,12 @@ func ProtoRule(rule *RuleBuilder, protoFile Path, flags ProtoFlags, deps Paths,
// Bp2buildProtoInfo contains information necessary to pass on to language specific conversion.
type Bp2buildProtoInfo struct {
Type *string
Name string
Proto_libs bazel.LabelList
}
type ProtoAttrs struct {
Srcs bazel.LabelListAttribute
Import_prefix *string
Strip_import_prefix *string
Deps bazel.LabelListAttribute
}
@@ -172,6 +173,35 @@ var includeDirsToProtoDeps = map[string]string{
"external/protobuf/src": "//external/protobuf:libprotobuf-proto",
}
// Partitions srcs by the pkg it is in
// srcs has been created using `TransformSubpackagePaths`
// This function uses existence of Android.bp/BUILD files to create a label that is compatible with the package structure of bp2build workspace
func partitionSrcsByPackage(currentDir string, srcs bazel.LabelList) map[string]bazel.LabelList {
getPackageFromLabel := func(label string) string {
// Remove any preceding //
label = strings.TrimPrefix(label, "//")
split := strings.Split(label, ":")
if len(split) == 1 {
// e.g. foo.proto
return currentDir
} else if split[0] == "" {
// e.g. :foo.proto
return currentDir
} else {
return split[0]
}
}
pkgToSrcs := map[string]bazel.LabelList{}
for _, src := range srcs.Includes {
pkg := getPackageFromLabel(src.Label)
list := pkgToSrcs[pkg]
list.Add(&src)
pkgToSrcs[pkg] = list
}
return pkgToSrcs
}
// Bp2buildProtoProperties converts proto properties, creating a proto_library and returning the
// information necessary for language-specific handling.
func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, m *ModuleBase, srcs bazel.LabelListAttribute) (Bp2buildProtoInfo, bool) {
@@ -197,54 +227,73 @@ func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, m *ModuleBase, srcs baz
}
}
info.Name = m.Name() + "_proto"
name := m.Name() + "_proto"
depsFromFilegroup := protoLibraries
if len(directProtoSrcs.Includes) > 0 {
attrs := ProtoAttrs{
Srcs: bazel.MakeLabelListAttribute(directProtoSrcs),
}
attrs.Deps.Append(bazel.MakeLabelListAttribute(protoLibraries))
pkgToSrcs := partitionSrcsByPackage(ctx.ModuleDir(), directProtoSrcs)
for _, pkg := range SortedStringKeys(pkgToSrcs) {
srcs := pkgToSrcs[pkg]
attrs := ProtoAttrs{
Srcs: bazel.MakeLabelListAttribute(srcs),
}
attrs.Deps.Append(bazel.MakeLabelListAttribute(depsFromFilegroup))
for axis, configToProps := range m.GetArchVariantProperties(ctx, &ProtoProperties{}) {
for _, rawProps := range configToProps {
var props *ProtoProperties
var ok bool
if props, ok = rawProps.(*ProtoProperties); !ok {
ctx.ModuleErrorf("Could not cast ProtoProperties to expected type")
}
if axis == bazel.NoConfigAxis {
info.Type = props.Proto.Type
if !proptools.BoolDefault(props.Proto.Canonical_path_from_root, canonicalPathFromRootDefault) {
// an empty string indicates to strips the package path
path := ""
attrs.Strip_import_prefix = &path
for axis, configToProps := range m.GetArchVariantProperties(ctx, &ProtoProperties{}) {
for _, rawProps := range configToProps {
var props *ProtoProperties
var ok bool
if props, ok = rawProps.(*ProtoProperties); !ok {
ctx.ModuleErrorf("Could not cast ProtoProperties to expected type")
}
if axis == bazel.NoConfigAxis {
info.Type = props.Proto.Type
for _, dir := range props.Proto.Include_dirs {
if dep, ok := includeDirsToProtoDeps[dir]; ok {
attrs.Deps.Add(bazel.MakeLabelAttribute(dep))
} else {
ctx.PropertyErrorf("Could not find the proto_library target for include dir", dir)
if !proptools.BoolDefault(props.Proto.Canonical_path_from_root, canonicalPathFromRootDefault) {
// an empty string indicates to strips the package path
path := ""
attrs.Strip_import_prefix = &path
}
for _, dir := range props.Proto.Include_dirs {
if dep, ok := includeDirsToProtoDeps[dir]; ok {
attrs.Deps.Add(bazel.MakeLabelAttribute(dep))
} else {
ctx.PropertyErrorf("Could not find the proto_library target for include dir", dir)
}
}
} else if props.Proto.Type != info.Type && props.Proto.Type != nil {
ctx.ModuleErrorf("Cannot handle arch-variant types for protos at this time.")
}
} else if props.Proto.Type != info.Type && props.Proto.Type != nil {
ctx.ModuleErrorf("Cannot handle arch-variant types for protos at this time.")
}
}
tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module())
// Since we are creating the proto_library in a subpackage, create an import_prefix relative to the current package
if rel, err := filepath.Rel(ctx.ModuleDir(), pkg); err != nil {
ctx.ModuleErrorf("Could not get relative path for %v %v", pkg, err)
} else if rel != "." {
attrs.Import_prefix = &rel
}
ctx.CreateBazelTargetModule(
bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
CommonAttributes{Name: name, Dir: proptools.StringPtr(pkg), Tags: tags},
&attrs,
)
l := ""
if pkg == ctx.ModuleDir() { // same package that the original module lives in
l = ":" + name
} else {
l = "//" + pkg + ":" + name
}
protoLibraries.Add(&bazel.Label{
Label: l,
})
}
tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module())
ctx.CreateBazelTargetModule(
bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
CommonAttributes{Name: info.Name, Tags: tags},
&attrs,
)
protoLibraries.Add(&bazel.Label{
Label: ":" + info.Name,
})
}
info.Proto_libs = protoLibraries