xref: /aosp_15_r20/build/soong/cc/proto.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1// Copyright 2016 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package cc
16
17import (
18	"github.com/google/blueprint/pathtools"
19	"github.com/google/blueprint/proptools"
20
21	"android/soong/android"
22
23	"strings"
24)
25
26const (
27	protoTypeDefault = "lite"
28)
29
30// genProto creates a rule to convert a .proto file to generated .pb.cc and .pb.h files and returns
31// the paths to the generated files.
32func genProto(ctx android.ModuleContext, protoFile android.Path, flags builderFlags) (cc, header android.WritablePath) {
33	var ccFile, headerFile android.ModuleGenPath
34
35	srcSuffix := ".cc"
36	if flags.protoC {
37		srcSuffix = ".c"
38	}
39
40	srcInfix := "pb"
41	for _, value := range flags.proto.Flags {
42		if strings.HasPrefix(value, "--plugin=") && strings.HasSuffix(value, "protoc-gen-grpc-cpp-plugin") {
43			srcInfix = "grpc.pb"
44			break
45		}
46	}
47
48	if flags.proto.CanonicalPathFromRoot {
49		ccFile = android.GenPathWithExt(ctx, "proto", protoFile, srcInfix+srcSuffix)
50		headerFile = android.GenPathWithExt(ctx, "proto", protoFile, srcInfix+".h")
51	} else {
52		rel := protoFile.Rel()
53		ccFile = android.PathForModuleGen(ctx, "proto", pathtools.ReplaceExtension(rel, srcInfix+srcSuffix))
54		headerFile = android.PathForModuleGen(ctx, "proto", pathtools.ReplaceExtension(rel, srcInfix+".h"))
55	}
56
57	protoDeps := flags.proto.Deps
58	if flags.protoOptionsFile {
59		optionsFile := pathtools.ReplaceExtension(protoFile.String(), "options")
60		optionsPath := android.PathForSource(ctx, optionsFile)
61		protoDeps = append(android.Paths{optionsPath}, protoDeps...)
62	}
63
64	outDir := flags.proto.Dir
65	depFile := ccFile.ReplaceExtension(ctx, "d")
66	outputs := android.WritablePaths{ccFile, headerFile}
67
68	rule := android.NewRuleBuilder(pctx, ctx)
69
70	android.ProtoRule(rule, protoFile, flags.proto, protoDeps, outDir, depFile, outputs)
71
72	rule.Build("protoc_"+protoFile.Rel(), "protoc "+protoFile.Rel())
73
74	return ccFile, headerFile
75}
76
77func protoDeps(ctx DepsContext, deps Deps, p *android.ProtoProperties, static bool) Deps {
78	var lib string
79
80	if String(p.Proto.Plugin) == "" {
81		switch proptools.StringDefault(p.Proto.Type, protoTypeDefault) {
82		case "full":
83			if ctx.useSdk() {
84				lib = "libprotobuf-cpp-full-ndk"
85				static = true
86			} else {
87				lib = "libprotobuf-cpp-full"
88			}
89		case "lite":
90			if ctx.useSdk() {
91				lib = "libprotobuf-cpp-lite-ndk"
92				static = true
93			} else {
94				lib = "libprotobuf-cpp-lite"
95			}
96		case "nanopb-c":
97			lib = "libprotobuf-c-nano"
98			static = true
99		case "nanopb-c-enable_malloc":
100			lib = "libprotobuf-c-nano-enable_malloc"
101			static = true
102		case "nanopb-c-16bit":
103			lib = "libprotobuf-c-nano-16bit"
104			static = true
105		case "nanopb-c-enable_malloc-16bit":
106			lib = "libprotobuf-c-nano-enable_malloc-16bit"
107			static = true
108		case "nanopb-c-32bit":
109			lib = "libprotobuf-c-nano-32bit"
110			static = true
111		case "nanopb-c-enable_malloc-32bit":
112			lib = "libprotobuf-c-nano-enable_malloc-32bit"
113			static = true
114		default:
115			ctx.PropertyErrorf("proto.type", "unknown proto type %q",
116				String(p.Proto.Type))
117		}
118
119		if static {
120			deps.StaticLibs = append(deps.StaticLibs, lib)
121			deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, lib)
122		} else {
123			deps.SharedLibs = append(deps.SharedLibs, lib)
124			deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, lib)
125		}
126	}
127
128	return deps
129}
130
131func protoFlags(ctx ModuleContext, flags Flags, p *android.ProtoProperties) Flags {
132	flags.Local.CFlags = append(flags.Local.CFlags, "-DGOOGLE_PROTOBUF_NO_RTTI")
133
134	flags.proto = android.GetProtoFlags(ctx, p)
135	if flags.proto.CanonicalPathFromRoot {
136		flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-I"+flags.proto.SubDir.String())
137	}
138	flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-I"+flags.proto.Dir.String())
139
140	if String(p.Proto.Plugin) == "" {
141		var plugin string
142
143		switch String(p.Proto.Type) {
144		case "nanopb-c", "nanopb-c-enable_malloc", "nanopb-c-16bit", "nanopb-c-enable_malloc-16bit", "nanopb-c-32bit", "nanopb-c-enable_malloc-32bit":
145			flags.protoC = true
146			flags.protoOptionsFile = true
147			flags.proto.OutTypeFlag = "--nanopb_out"
148			// Disable nanopb timestamps to support remote caching.
149			flags.proto.OutParams = append(flags.proto.OutParams, "-T")
150			plugin = "protoc-gen-nanopb"
151		case "full":
152			flags.proto.OutTypeFlag = "--cpp_out"
153		case "lite":
154			flags.proto.OutTypeFlag = "--cpp_out"
155			flags.proto.OutParams = append(flags.proto.OutParams, "lite")
156		case "":
157			// TODO(b/119714316): this should be equivalent to "lite" in
158			// order to match protoDeps, but some modules are depending on
159			// this behavior
160			flags.proto.OutTypeFlag = "--cpp_out"
161		default:
162			ctx.PropertyErrorf("proto.type", "unknown proto type %q",
163				String(p.Proto.Type))
164		}
165
166		if plugin != "" {
167			path := ctx.Config().HostToolPath(ctx, plugin)
168			flags.proto.Deps = append(flags.proto.Deps, path)
169			flags.proto.Flags = append(flags.proto.Flags, "--plugin="+path.String())
170		}
171	}
172
173	return flags
174}
175