Add support for .proto files

.proto files are translated to .pb.cc and .pb.h files, which are then
compiled normally.

Bug: 32286026
Test: mmma -j system/extras/perfprofd
Change-Id: I538071424d667aacf35b4b8bfebe217f5f092726
diff --git a/cc/proto.go b/cc/proto.go
new file mode 100644
index 0000000..3d3ca59
--- /dev/null
+++ b/cc/proto.go
@@ -0,0 +1,131 @@
+// Copyright 2016 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 cc
+
+import (
+	"strings"
+
+	"github.com/google/blueprint"
+
+	"android/soong/android"
+)
+
+func init() {
+	pctx.HostBinToolVariable("protocCmd", "aprotoc")
+}
+
+var (
+	proto = pctx.AndroidStaticRule("protoc",
+		blueprint.RuleParams{
+			Command:     "$protocCmd --cpp_out=$outDir $protoFlags $in",
+			CommandDeps: []string{"$protocCmd"},
+			Description: "protoc $out",
+		}, "protoFlags", "outDir")
+)
+
+// 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
+// export a library for every type of external user (lite vs. full, c vs. c++ vs. java).  It would
+// be better to support a proto module type that exported a proto file along with some include dirs,
+// and then external modules could depend on the proto module but use their own settings to
+// generate the source.
+
+func genProto(ctx android.ModuleContext, protoFile android.Path,
+	protoFlags string) (android.ModuleGenPath, android.ModuleGenPath) {
+
+	outDir := android.PathForModuleGen(ctx, "proto")
+	baseName := strings.TrimSuffix(protoFile.Base(), protoFile.Ext())
+
+	outFile := android.PathForModuleGen(ctx, "proto", ctx.ModuleDir(), baseName+".pb.cc")
+	headerFile := android.PathForModuleGen(ctx, "proto", ctx.ModuleDir(), baseName+".pb.h")
+	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+		Rule:    proto,
+		Outputs: android.WritablePaths{outFile, headerFile},
+		Input:   protoFile,
+		Args: map[string]string{
+			"outDir":     outDir.String(),
+			"protoFlags": protoFlags,
+		},
+	})
+
+	return outFile, headerFile
+}
+
+// protoDir returns the module's "gen/proto" directory
+func protoDir(ctx android.ModuleContext) android.ModuleGenPath {
+	return android.PathForModuleGen(ctx, "proto")
+}
+
+// protoSubDir returns the module's "gen/proto/path/to/module" directory
+func protoSubDir(ctx android.ModuleContext) android.ModuleGenPath {
+	return android.PathForModuleGen(ctx, "proto", ctx.ModuleDir())
+}
+
+type ProtoProperties struct {
+	Proto struct {
+		// Proto generator type (full, lite)
+		Type string
+		// Link statically against the protobuf runtime
+		Static bool
+	}
+}
+
+func protoDeps(ctx BaseModuleContext, deps Deps, p *ProtoProperties) Deps {
+	var lib string
+	var static bool
+
+	switch p.Proto.Type {
+	case "full":
+		if ctx.sdk() {
+			lib = "libprotobuf-cpp-full-ndk"
+			static = true
+		} else {
+			lib = "libprotobuf-cpp-full"
+		}
+	case "lite", "":
+		if ctx.sdk() {
+			lib = "libprotobuf-cpp-lite-ndk"
+			static = true
+		} else {
+			lib = "libprotobuf-cpp-lite"
+			if p.Proto.Static {
+				static = true
+			}
+		}
+	default:
+		ctx.PropertyErrorf("proto.type", "unknown proto type %q", p.Proto.Type)
+	}
+
+	if static {
+		deps.StaticLibs = append(deps.StaticLibs, lib)
+		deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, lib)
+	} else {
+		deps.SharedLibs = append(deps.SharedLibs, lib)
+		deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, lib)
+	}
+
+	return deps
+}
+
+func protoFlags(ctx ModuleContext, flags Flags, p *ProtoProperties) Flags {
+	flags.CFlags = append(flags.CFlags, "-DGOOGLE_PROTOBUF_NO_RTTI")
+	flags.GlobalFlags = append(flags.GlobalFlags,
+		"-I"+protoSubDir(ctx).String(),
+		"-I"+protoDir(ctx).String(),
+	)
+
+	return flags
+}