convert java proto libraries with bp2build
Allow java_libraries that depend on protobufs to be converted with
bp2build.
Bug: 215230097
Test: build/bazel/ci/bp2build.sh
Change-Id: I3ce52389e7e4e82755605ee277c1e527a6aebc6b
diff --git a/android/filegroup.go b/android/filegroup.go
index c932ffa..d2ff97d 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -18,6 +18,8 @@
"strings"
"android/soong/bazel"
+
+ "github.com/google/blueprint"
)
func init() {
@@ -28,6 +30,11 @@
ctx.RegisterModuleType("filegroup", FileGroupFactory)
})
+// IsFilegroup checks that a module is a filegroup type
+func IsFilegroup(ctx bazel.OtherModuleContext, m blueprint.Module) bool {
+ return ctx.OtherModuleType(m) == "filegroup"
+}
+
// https://docs.bazel.build/versions/master/be/general.html#filegroup
type bazelFilegroupAttributes struct {
Srcs bazel.LabelListAttribute
diff --git a/android/proto.go b/android/proto.go
index f466261..c3759f8 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -16,6 +16,7 @@
import (
"android/soong/bazel"
+ "regexp"
"strings"
"github.com/google/blueprint"
@@ -26,6 +27,14 @@
canonicalPathFromRootDefault = true
)
+var (
+ // ignoring case, checks for proto or protos as an independent word in the name, whether at the
+ // beginning, end, or middle. e.g. "proto.foo", "bar-protos", "baz_proto_srcs" would all match
+ filegroupLikelyProtoPattern = regexp.MustCompile("(?i)(^|[^a-z])proto(s)?([^a-z]|$)")
+
+ ProtoSrcLabelPartition = bazel.LabelPartition{Extensions: []string{".proto"}, LabelMapper: isProtoFilegroup}
+)
+
// TODO(ccross): protos are often used to communicate between multiple modules. If the only
// way to convert a proto to source is to reference it as a source file, and external modules cannot
// reference source files in other modules, then every module that owns a proto file will need to
@@ -165,12 +174,11 @@
// Bp2buildProtoProperties converts proto properties, creating a proto_library and returning the
// information necessary for language-specific handling.
-func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, module Module, srcs bazel.LabelListAttribute) (Bp2buildProtoInfo, bool) {
+func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, m *ModuleBase, srcs bazel.LabelListAttribute) (Bp2buildProtoInfo, bool) {
var info Bp2buildProtoInfo
if srcs.IsEmpty() {
return info, false
}
- m := module.base()
info.Name = m.Name() + "_proto"
attrs := protoAttrs{
@@ -205,3 +213,13 @@
return info, true
}
+
+func isProtoFilegroup(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
+ m, exists := ctx.ModuleFromName(label.OriginalModuleName)
+ labelStr := label.Label
+ if !exists || !IsFilegroup(ctx, m) {
+ return labelStr, false
+ }
+ likelyProtos := filegroupLikelyProtoPattern.MatchString(label.OriginalModuleName)
+ return labelStr, likelyProtos
+}
diff --git a/bp2build/java_proto_conversion_test.go b/bp2build/java_proto_conversion_test.go
new file mode 100644
index 0000000..93b0677
--- /dev/null
+++ b/bp2build/java_proto_conversion_test.go
@@ -0,0 +1,124 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bp2build
+
+import (
+ "fmt"
+ "testing"
+
+ "android/soong/android"
+ "android/soong/java"
+)
+
+func runJavaProtoTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ (&tc).moduleTypeUnderTest = "java_library_static"
+ (&tc).moduleTypeUnderTestFactory = java.LibraryFactory
+ runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
+}
+
+func TestJavaProto(t *testing.T) {
+ testCases := []struct {
+ protoType string
+ javaLibraryType string
+ javaLibraryNameExtension string
+ }{
+ {
+ protoType: "nano",
+ javaLibraryType: "java_nano_proto_library",
+ javaLibraryNameExtension: "java_proto_nano",
+ },
+ {
+ protoType: "micro",
+ javaLibraryType: "java_micro_proto_library",
+ javaLibraryNameExtension: "java_proto_micro",
+ },
+ {
+ protoType: "lite",
+ javaLibraryType: "java_lite_proto_library",
+ javaLibraryNameExtension: "java_proto_lite",
+ },
+ {
+ protoType: "stream",
+ javaLibraryType: "java_stream_proto_library",
+ javaLibraryNameExtension: "java_proto_stream",
+ },
+ {
+ protoType: "full",
+ javaLibraryType: "java_proto_library",
+ javaLibraryNameExtension: "java_proto",
+ },
+ }
+
+ bp := `java_library_static {
+ name: "java-protos",
+ proto: {
+ type: "%s",
+ },
+ srcs: ["a.proto"],
+}`
+
+ protoLibrary := makeBazelTarget("proto_library", "java-protos_proto", attrNameToString{
+ "srcs": `["a.proto"]`,
+ "strip_import_prefix": `""`,
+ })
+
+ for _, tc := range testCases {
+ javaLibraryName := fmt.Sprintf("java-protos_%s", tc.javaLibraryNameExtension)
+
+ runJavaProtoTestCase(t, bp2buildTestCase{
+ description: fmt.Sprintf("java_proto %s", tc.protoType),
+ blueprint: fmt.Sprintf(bp, tc.protoType),
+ expectedBazelTargets: []string{
+ protoLibrary,
+ makeBazelTarget(
+ tc.javaLibraryType,
+ javaLibraryName,
+ attrNameToString{
+ "deps": `[":java-protos_proto"]`,
+ }),
+ makeBazelTarget("java_library", "java-protos", attrNameToString{
+ "deps": fmt.Sprintf(`[":%s"]`, javaLibraryName),
+ }),
+ },
+ })
+ }
+}
+
+func TestJavaProtoDefault(t *testing.T) {
+ runJavaProtoTestCase(t, bp2buildTestCase{
+ description: "java_proto",
+ blueprint: `java_library_static {
+ name: "java-protos",
+ srcs: ["a.proto"],
+}
+`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "java-protos_proto", attrNameToString{
+ "srcs": `["a.proto"]`,
+ "strip_import_prefix": `""`,
+ }),
+ makeBazelTarget(
+ "java_lite_proto_library",
+ "java-protos_java_proto_lite",
+ attrNameToString{
+ "deps": `[":java-protos_proto"]`,
+ }),
+ makeBazelTarget("java_library", "java-protos", attrNameToString{
+ "deps": `[":java-protos_java_proto_lite"]`,
+ }),
+ },
+ })
+}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 42fc0e4..379d6f2 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -16,7 +16,6 @@
import (
"fmt"
"path/filepath"
- "regexp"
"strings"
"android/soong/android"
@@ -34,12 +33,6 @@
protoSrcPartition = "proto"
)
-var (
- // ignoring case, checks for proto or protos as an independent word in the name, whether at the
- // beginning, end, or middle. e.g. "proto.foo", "bar-protos", "baz_proto_srcs" would all match
- filegroupLikelyProtoPattern = regexp.MustCompile("(?i)(^|[^a-z])proto(s)?([^a-z]|$)")
-)
-
// staticOrSharedAttributes are the Bazel-ified versions of StaticOrSharedProperties --
// properties which apply to either the shared or static version of a cc_library module.
type staticOrSharedAttributes struct {
@@ -61,46 +54,32 @@
Enabled bazel.BoolAttribute
}
+// groupSrcsByExtension partitions `srcs` into groups based on file extension.
func groupSrcsByExtension(ctx android.BazelConversionPathContext, srcs bazel.LabelListAttribute) bazel.PartitionToLabelListAttribute {
- // Check that a module is a filegroup type
- isFilegroup := func(m blueprint.Module) bool {
- return ctx.OtherModuleType(m) == "filegroup"
- }
-
// Convert filegroup dependencies into extension-specific filegroups filtered in the filegroup.bzl
// macro.
addSuffixForFilegroup := func(suffix string) bazel.LabelMapper {
return func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
m, exists := ctx.ModuleFromName(label.OriginalModuleName)
labelStr := label.Label
- if !exists || !isFilegroup(m) {
+ if !exists || !android.IsFilegroup(ctx, m) {
return labelStr, false
}
return labelStr + suffix, true
}
}
- isProtoFilegroup := func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
- m, exists := ctx.ModuleFromName(label.OriginalModuleName)
- labelStr := label.Label
- if !exists || !isFilegroup(m) {
- return labelStr, false
- }
- likelyProtos := filegroupLikelyProtoPattern.MatchString(label.OriginalModuleName)
- return labelStr, likelyProtos
- }
-
// TODO(b/190006308): Handle language detection of sources in a Bazel rule.
- partitioned := bazel.PartitionLabelListAttribute(ctx, &srcs, bazel.LabelPartitions{
- protoSrcPartition: bazel.LabelPartition{Extensions: []string{".proto"}, LabelMapper: isProtoFilegroup},
+ labels := bazel.LabelPartitions{
+ protoSrcPartition: android.ProtoSrcLabelPartition,
cSrcPartition: bazel.LabelPartition{Extensions: []string{".c"}, LabelMapper: addSuffixForFilegroup("_c_srcs")},
asSrcPartition: bazel.LabelPartition{Extensions: []string{".s", ".S"}, LabelMapper: addSuffixForFilegroup("_as_srcs")},
// C++ is the "catch-all" group, and comprises generated sources because we don't
// know the language of these sources until the genrule is executed.
cppSrcPartition: bazel.LabelPartition{Extensions: []string{".cpp", ".cc", ".cxx", ".mm"}, LabelMapper: addSuffixForFilegroup("_cpp_srcs"), Keep_remainder: true},
- })
+ }
- return partitioned
+ return bazel.PartitionLabelListAttribute(ctx, &srcs, labels)
}
// bp2BuildParseLibProps returns the attributes for a variant of a cc_library.
diff --git a/cc/proto.go b/cc/proto.go
index 3cf1453..8e6d5ed 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -177,7 +177,7 @@
func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute) bp2buildProtoDeps {
var ret bp2buildProtoDeps
- protoInfo, ok := android.Bp2buildProtoProperties(ctx, m, protoSrcs)
+ protoInfo, ok := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, protoSrcs)
if !ok {
return ret
}
diff --git a/java/java.go b/java/java.go
index e55f045..d0f0abc 100644
--- a/java/java.go
+++ b/java/java.go
@@ -2013,8 +2013,16 @@
func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) *javaLibraryAttributes {
//TODO(b/209577426): Support multiple arch variants
srcs := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs))
+
+ javaSrcPartition := "java"
+ protoSrcPartition := "proto"
+ srcPartitions := bazel.PartitionLabelListAttribute(ctx, &srcs, bazel.LabelPartitions{
+ javaSrcPartition: bazel.LabelPartition{Extensions: []string{".java"}, Keep_remainder: true},
+ protoSrcPartition: android.ProtoSrcLabelPartition,
+ })
+
attrs := &javaLibraryAttributes{
- Srcs: srcs,
+ Srcs: srcPartitions[javaSrcPartition],
}
if m.properties.Javacflags != nil {
@@ -2029,6 +2037,12 @@
//TODO(b/217236083) handle static libs similarly to Soong
deps.Append(android.BazelLabelForModuleDeps(ctx, m.properties.Static_libs))
}
+
+ protoDeps := bp2buildProto(ctx, &m.Module, srcPartitions[protoSrcPartition])
+ if protoDeps != nil {
+ deps.Add(protoDeps)
+ }
+
attrs.Deps = bazel.MakeLabelListAttribute(deps)
return attrs
diff --git a/java/proto.go b/java/proto.go
index 8d23803..5ba486f 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -19,6 +19,13 @@
"strconv"
"android/soong/android"
+ "android/soong/bazel"
+
+ "github.com/google/blueprint/proptools"
+)
+
+const (
+ protoTypeDefault = "lite"
)
func genProto(ctx android.ModuleContext, protoFiles android.Paths, flags android.ProtoFlags) android.Paths {
@@ -134,3 +141,52 @@
return flags
}
+
+type protoAttributes struct {
+ Deps bazel.LabelListAttribute
+}
+
+func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute) *bazel.Label {
+ protoInfo, ok := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, protoSrcs)
+ if !ok {
+ return nil
+ }
+
+ typ := proptools.StringDefault(protoInfo.Type, protoTypeDefault)
+ var rule_class string
+ suffix := "_java_proto"
+ switch typ {
+ case "nano":
+ suffix += "_nano"
+ rule_class = "java_nano_proto_library"
+ case "micro":
+ suffix += "_micro"
+ rule_class = "java_micro_proto_library"
+ case "lite":
+ suffix += "_lite"
+ rule_class = "java_lite_proto_library"
+ case "stream":
+ suffix += "_stream"
+ rule_class = "java_stream_proto_library"
+ case "full":
+ rule_class = "java_proto_library"
+ default:
+ ctx.PropertyErrorf("proto.type", "cannot handle conversion at this time: %q", typ)
+ }
+
+ protoLabel := bazel.Label{Label: ":" + m.Name() + "_proto"}
+ var protoAttrs protoAttributes
+ protoAttrs.Deps.SetValue(bazel.LabelList{Includes: []bazel.Label{protoLabel}})
+
+ name := m.Name() + suffix
+
+ ctx.CreateBazelTargetModule(
+ bazel.BazelTargetModuleProperties{
+ Rule_class: rule_class,
+ Bzl_load_location: "//build/bazel/rules/java:proto.bzl",
+ },
+ android.CommonAttributes{Name: name},
+ &protoAttrs)
+
+ return &bazel.Label{Label: ":" + name}
+}