Handle .proto files that end up in a different package
Bazel poses a strict requirement that .proto files and proto_library
must be in the same package. This CL handles this automatically by
creating the proto_library in a separate dir/package if necessary
Implementation details
- Partition the `srcs` by package. `srcs` has been computed using
`transformSubpackagePath`, so the information about packages is
available at this point
- Create a proto_library in each package by using
`CommonAttributes.Dir`. Collect all these additional libraries
and put them in `info.Proto_libraries` so that they get added as deps
of (cc|python|...)_proto_library
- Add an import_prefix to the proto_library in subpackages relative to
the current directory. This relies on the assumption that every src is
beneath the current directory (Soong will complain if a path in
Android.bp contains ../)
filegroup module type uses a separate code-path to create proto_library.
This will be handled in the next CL in stack.
Test: bp2build unit tests
Test: TH
Test: Built the failing internal module mentioned in
b/292583584#comment1
Bug: 292583584
Change-Id: I437fc89092321b26c5f0511387cde9e84084d6f9
diff --git a/android/proto.go b/android/proto.go
index cebbd59..aad521b 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -15,6 +15,7 @@
package android
import (
+ "path/filepath"
"strings"
"android/soong/bazel"
@@ -156,12 +157,12 @@
// 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 @@
"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 @@
}
}
- 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