bp2build: support full/lite protos in cc libs

Test: bp2build.sh
Bug: 200601772
Change-Id: I3a7e00546726bc63b5eb8d5604557c5988a5320b
diff --git a/cc/binary.go b/cc/binary.go
index a5afb07..63657e4 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -18,6 +18,7 @@
 	"path/filepath"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
 	"android/soong/bazel"
@@ -578,9 +579,16 @@
 	}
 
 	baseAttrs := bp2BuildParseBaseProps(ctx, m)
+	binaryLinkerAttrs := bp2buildBinaryLinkerProps(ctx, m)
+
+	if proptools.BoolDefault(binaryLinkerAttrs.Linkshared, true) {
+		baseAttrs.implementationDynamicDeps.Add(baseAttrs.protoDependency)
+	} else {
+		baseAttrs.implementationDeps.Add(baseAttrs.protoDependency)
+	}
 
 	attrs := &binaryAttributes{
-		binaryLinkerAttrs: bp2buildBinaryLinkerProps(ctx, m),
+		binaryLinkerAttrs: binaryLinkerAttrs,
 
 		Srcs:    baseAttrs.srcs,
 		Srcs_c:  baseAttrs.cSrcs,
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 888c3ba..f9bbe87 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -27,9 +27,10 @@
 )
 
 const (
-	cSrcPartition   = "c"
-	asSrcPartition  = "as"
-	cppSrcPartition = "cpp"
+	cSrcPartition     = "c"
+	asSrcPartition    = "as"
+	cppSrcPartition   = "cpp"
+	protoSrcPartition = "proto"
 )
 
 // staticOrSharedAttributes are the Bazel-ified versions of StaticOrSharedProperties --
@@ -41,52 +42,53 @@
 	Hdrs    bazel.LabelListAttribute
 	Copts   bazel.StringListAttribute
 
-	Deps                        bazel.LabelListAttribute
-	Implementation_deps         bazel.LabelListAttribute
-	Dynamic_deps                bazel.LabelListAttribute
-	Implementation_dynamic_deps bazel.LabelListAttribute
-	Whole_archive_deps          bazel.LabelListAttribute
+	Deps                              bazel.LabelListAttribute
+	Implementation_deps               bazel.LabelListAttribute
+	Dynamic_deps                      bazel.LabelListAttribute
+	Implementation_dynamic_deps       bazel.LabelListAttribute
+	Whole_archive_deps                bazel.LabelListAttribute
+	Implementation_whole_archive_deps bazel.LabelListAttribute
 
 	System_dynamic_deps bazel.LabelListAttribute
 }
 
 func groupSrcsByExtension(ctx android.BazelConversionPathContext, srcs bazel.LabelListAttribute) bazel.PartitionToLabelListAttribute {
-	// Check that a module is a filegroup type named <label>.
-	isFilegroupNamed := func(m android.Module, fullLabel string) bool {
-		if ctx.OtherModuleType(m) != "filegroup" {
-			return false
-		}
-		labelParts := strings.Split(fullLabel, ":")
-		if len(labelParts) > 2 {
-			// There should not be more than one colon in a label.
-			ctx.ModuleErrorf("%s is not a valid Bazel label for a filegroup", fullLabel)
-		}
-		return m.Name() == labelParts[len(labelParts)-1]
+	// 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 string) (string, bool) {
-			m, exists := ctx.ModuleFromName(label)
-			if !exists {
-				return label, false
+		return 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
 			}
-			aModule, _ := m.(android.Module)
-			if !isFilegroupNamed(aModule, label) {
-				return label, false
-			}
-			return label + suffix, true
+			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 := strings.HasSuffix(labelStr, "proto") || strings.HasSuffix(labelStr, "protos")
+		return labelStr, likelyProtos
+	}
+
 	// TODO(b/190006308): Handle language detection of sources in a Bazel rule.
 	partitioned := bazel.PartitionLabelListAttribute(ctx, &srcs, bazel.LabelPartitions{
 		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},
+		cppSrcPartition:   bazel.LabelPartition{Extensions: []string{".cpp", ".cc", ".cxx", ".mm"}, LabelMapper: addSuffixForFilegroup("_cpp_srcs"), Keep_remainder: true},
+		protoSrcPartition: bazel.LabelPartition{Extensions: []string{".proto"}, LabelMapper: isProtoFilegroup},
 	})
 
 	return partitioned
@@ -195,6 +197,11 @@
 	attrs.Srcs_c = partitionedSrcs[cSrcPartition]
 	attrs.Srcs_as = partitionedSrcs[asSrcPartition]
 
+	if !partitionedSrcs[protoSrcPartition].IsEmpty() {
+		// TODO(b/208815215): determine whether this is used and add support if necessary
+		ctx.ModuleErrorf("Migrating static/shared only proto srcs is not currently supported")
+	}
+
 	return attrs
 }
 
@@ -230,6 +237,8 @@
 type baseAttributes struct {
 	compilerAttributes
 	linkerAttributes
+
+	protoDependency *bazel.LabelAttribute
 }
 
 // Convenience struct to hold all attributes parsed from compiler properties.
@@ -257,6 +266,8 @@
 
 	localIncludes    bazel.StringListAttribute
 	absoluteIncludes bazel.StringListAttribute
+
+	protoSrcs bazel.LabelListAttribute
 }
 
 func parseCommandLineFlags(soongFlags []string) []string {
@@ -337,6 +348,8 @@
 	ca.srcs.ResolveExcludes()
 	partitionedSrcs := groupSrcsByExtension(ctx, ca.srcs)
 
+	ca.protoSrcs = partitionedSrcs[protoSrcPartition]
+
 	for p, lla := range partitionedSrcs {
 		// if there are no sources, there is no need for headers
 		if lla.IsEmpty() {
@@ -400,7 +413,7 @@
 }
 
 // bp2BuildParseCompilerProps returns copts, srcs and hdrs and other attributes.
-func bp2BuildParseBaseProps(ctx android.BazelConversionPathContext, module *Module) baseAttributes {
+func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) baseAttributes {
 	archVariantCompilerProps := module.GetArchVariantProperties(ctx, &BaseCompilerProperties{})
 	archVariantLinkerProps := module.GetArchVariantProperties(ctx, &BaseLinkerProperties{})
 
@@ -456,20 +469,30 @@
 	(&compilerAttrs).finalize(ctx, implementationHdrs)
 	(&linkerAttrs).finalize()
 
+	protoDep := bp2buildProto(ctx, module, compilerAttrs.protoSrcs)
+
+	// bp2buildProto will only set wholeStaticLib or implementationWholeStaticLib, but we don't know
+	// which. This will add the newly generated proto library to the appropriate attribute and nothing
+	// to the other
+	(&linkerAttrs).wholeArchiveDeps.Add(protoDep.wholeStaticLib)
+	(&linkerAttrs).implementationWholeArchiveDeps.Add(protoDep.implementationWholeStaticLib)
+
 	return baseAttributes{
 		compilerAttrs,
 		linkerAttrs,
+		protoDep.protoDep,
 	}
 }
 
 // Convenience struct to hold all attributes parsed from linker properties.
 type linkerAttributes struct {
-	deps                      bazel.LabelListAttribute
-	implementationDeps        bazel.LabelListAttribute
-	dynamicDeps               bazel.LabelListAttribute
-	implementationDynamicDeps bazel.LabelListAttribute
-	wholeArchiveDeps          bazel.LabelListAttribute
-	systemDynamicDeps         bazel.LabelListAttribute
+	deps                           bazel.LabelListAttribute
+	implementationDeps             bazel.LabelListAttribute
+	dynamicDeps                    bazel.LabelListAttribute
+	implementationDynamicDeps      bazel.LabelListAttribute
+	wholeArchiveDeps               bazel.LabelListAttribute
+	implementationWholeArchiveDeps bazel.LabelListAttribute
+	systemDynamicDeps              bazel.LabelListAttribute
 
 	linkCrt                       bazel.BoolAttribute
 	useLibcrt                     bazel.BoolAttribute
diff --git a/cc/library.go b/cc/library.go
index 3dceda0..84aae0d 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -236,12 +236,13 @@
 
 	Hdrs bazel.LabelListAttribute
 
-	Deps                        bazel.LabelListAttribute
-	Implementation_deps         bazel.LabelListAttribute
-	Dynamic_deps                bazel.LabelListAttribute
-	Implementation_dynamic_deps bazel.LabelListAttribute
-	Whole_archive_deps          bazel.LabelListAttribute
-	System_dynamic_deps         bazel.LabelListAttribute
+	Deps                              bazel.LabelListAttribute
+	Implementation_deps               bazel.LabelListAttribute
+	Dynamic_deps                      bazel.LabelListAttribute
+	Implementation_dynamic_deps       bazel.LabelListAttribute
+	Whole_archive_deps                bazel.LabelListAttribute
+	Implementation_whole_archive_deps bazel.LabelListAttribute
+	System_dynamic_deps               bazel.LabelListAttribute
 
 	Export_includes        bazel.StringListAttribute
 	Export_system_includes bazel.StringListAttribute
@@ -303,6 +304,9 @@
 
 	srcs := compilerAttrs.srcs
 
+	sharedAttrs.Dynamic_deps.Add(baseAttributes.protoDependency)
+	staticAttrs.Deps.Add(baseAttributes.protoDependency)
+
 	asFlags := compilerAttrs.asFlags
 	if compilerAttrs.asSrcs.IsEmpty() && sharedAttrs.Srcs_as.IsEmpty() && staticAttrs.Srcs_as.IsEmpty() {
 		// Skip asflags for BUILD file simplicity if there are no assembly sources.
@@ -320,23 +324,24 @@
 		Conlyflags: compilerAttrs.conlyFlags,
 		Asflags:    asFlags,
 
-		Implementation_deps:         linkerAttrs.implementationDeps,
-		Deps:                        linkerAttrs.deps,
-		Implementation_dynamic_deps: linkerAttrs.implementationDynamicDeps,
-		Dynamic_deps:                linkerAttrs.dynamicDeps,
-		Whole_archive_deps:          linkerAttrs.wholeArchiveDeps,
-		System_dynamic_deps:         linkerAttrs.systemDynamicDeps,
-		Export_includes:             exportedIncludes.Includes,
-		Export_system_includes:      exportedIncludes.SystemIncludes,
-		Local_includes:              compilerAttrs.localIncludes,
-		Absolute_includes:           compilerAttrs.absoluteIncludes,
-		Linkopts:                    linkerAttrs.linkopts,
-		Link_crt:                    linkerAttrs.linkCrt,
-		Use_libcrt:                  linkerAttrs.useLibcrt,
-		Rtti:                        compilerAttrs.rtti,
-		Stl:                         compilerAttrs.stl,
-		Cpp_std:                     compilerAttrs.cppStd,
-		C_std:                       compilerAttrs.cStd,
+		Implementation_deps:               linkerAttrs.implementationDeps,
+		Deps:                              linkerAttrs.deps,
+		Implementation_dynamic_deps:       linkerAttrs.implementationDynamicDeps,
+		Dynamic_deps:                      linkerAttrs.dynamicDeps,
+		Whole_archive_deps:                linkerAttrs.wholeArchiveDeps,
+		Implementation_whole_archive_deps: linkerAttrs.implementationWholeArchiveDeps,
+		System_dynamic_deps:               linkerAttrs.systemDynamicDeps,
+		Export_includes:                   exportedIncludes.Includes,
+		Export_system_includes:            exportedIncludes.SystemIncludes,
+		Local_includes:                    compilerAttrs.localIncludes,
+		Absolute_includes:                 compilerAttrs.absoluteIncludes,
+		Linkopts:                          linkerAttrs.linkopts,
+		Link_crt:                          linkerAttrs.linkCrt,
+		Use_libcrt:                        linkerAttrs.useLibcrt,
+		Rtti:                              compilerAttrs.rtti,
+		Stl:                               compilerAttrs.stl,
+		Cpp_std:                           compilerAttrs.cppStd,
+		C_std:                             compilerAttrs.cStd,
 
 		Additional_linker_inputs: linkerAttrs.additionalLinkerInputs,
 
@@ -2405,16 +2410,18 @@
 		Copts:   compilerAttrs.copts,
 		Hdrs:    compilerAttrs.hdrs,
 
-		Deps:                        linkerAttrs.deps,
-		Implementation_deps:         linkerAttrs.implementationDeps,
-		Dynamic_deps:                linkerAttrs.dynamicDeps,
-		Implementation_dynamic_deps: linkerAttrs.implementationDynamicDeps,
-		Whole_archive_deps:          linkerAttrs.wholeArchiveDeps,
-		System_dynamic_deps:         linkerAttrs.systemDynamicDeps,
+		Deps:                              linkerAttrs.deps,
+		Implementation_deps:               linkerAttrs.implementationDeps,
+		Dynamic_deps:                      linkerAttrs.dynamicDeps,
+		Implementation_dynamic_deps:       linkerAttrs.implementationDynamicDeps,
+		Whole_archive_deps:                linkerAttrs.wholeArchiveDeps,
+		Implementation_whole_archive_deps: linkerAttrs.implementationWholeArchiveDeps,
+		System_dynamic_deps:               linkerAttrs.systemDynamicDeps,
 	}
 
 	var attrs interface{}
 	if isStatic {
+		commonAttrs.Deps.Add(baseAttributes.protoDependency)
 		attrs = &bazelCcLibraryStaticAttributes{
 			staticOrSharedAttributes: commonAttrs,
 
@@ -2435,6 +2442,8 @@
 			Features: linkerAttrs.features,
 		}
 	} else {
+		commonAttrs.Dynamic_deps.Add(baseAttributes.protoDependency)
+
 		attrs = &bazelCcLibrarySharedAttributes{
 			staticOrSharedAttributes: commonAttrs,
 
diff --git a/cc/proto.go b/cc/proto.go
index 4466144..f3410bc 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -16,8 +16,14 @@
 
 import (
 	"github.com/google/blueprint/pathtools"
+	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/bazel"
+)
+
+const (
+	protoTypeDefault = "lite"
 )
 
 // genProto creates a rule to convert a .proto file to generated .pb.cc and .pb.h files and returns
@@ -63,7 +69,7 @@
 	var lib string
 
 	if String(p.Proto.Plugin) == "" {
-		switch String(p.Proto.Type) {
+		switch proptools.StringDefault(p.Proto.Type, protoTypeDefault) {
 		case "full":
 			if ctx.useSdk() {
 				lib = "libprotobuf-cpp-full-ndk"
@@ -71,7 +77,7 @@
 			} else {
 				lib = "libprotobuf-cpp-full"
 			}
-		case "lite", "":
+		case "lite":
 			if ctx.useSdk() {
 				lib = "libprotobuf-cpp-lite-ndk"
 				static = true
@@ -157,3 +163,69 @@
 
 	return flags
 }
+
+type protoAttributes struct {
+	Deps bazel.LabelListAttribute
+}
+
+type bp2buildProtoDeps struct {
+	wholeStaticLib               *bazel.LabelAttribute
+	implementationWholeStaticLib *bazel.LabelAttribute
+	protoDep                     *bazel.LabelAttribute
+}
+
+func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute) bp2buildProtoDeps {
+	var ret bp2buildProtoDeps
+
+	protoInfo, ok := android.Bp2buildProtoProperties(ctx, m, protoSrcs)
+	if !ok {
+		return ret
+	}
+
+	var depName string
+	typ := proptools.StringDefault(protoInfo.Type, protoTypeDefault)
+	var rule_class string
+	suffix := "_cc_proto"
+	switch typ {
+	case "lite":
+		suffix += "_lite"
+		rule_class = "cc_lite_proto_library"
+		depName = "libprotobuf-cpp-lite"
+	case "full":
+		rule_class = "cc_proto_library"
+		depName = "libprotobuf-cpp-full"
+	default:
+		ctx.PropertyErrorf("proto.type", "cannot handle conversion at this time: %q", typ)
+	}
+
+	dep := android.BazelLabelForModuleDepSingle(ctx, depName)
+	ret.protoDep = &bazel.LabelAttribute{Value: &dep}
+
+	protoLabel := bazel.Label{Label: ":" + protoInfo.Name}
+	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:cc_proto.bzl",
+		},
+		android.CommonAttributes{Name: name},
+		&protoAttrs)
+
+	var privateHdrs bool
+	if lib, ok := m.linker.(*libraryDecorator); ok {
+		privateHdrs = !proptools.Bool(lib.Properties.Proto.Export_proto_headers)
+	}
+
+	labelAttr := &bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + name}}
+	if privateHdrs {
+		ret.implementationWholeStaticLib = labelAttr
+	} else {
+		ret.wholeStaticLib = labelAttr
+	}
+
+	return ret
+}