• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2017 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 android
16
17import (
18	"strings"
19
20	"github.com/google/blueprint"
21	"github.com/google/blueprint/proptools"
22)
23
24// TODO(ccross): protos are often used to communicate between multiple modules.  If the only
25// way to convert a proto to source is to reference it as a source file, and external modules cannot
26// reference source files in other modules, then every module that owns a proto file will need to
27// export a library for every type of external user (lite vs. full, c vs. c++ vs. java).  It would
28// be better to support a proto module type that exported a proto file along with some include dirs,
29// and then external modules could depend on the proto module but use their own settings to
30// generate the source.
31
32type ProtoFlags struct {
33	Flags                 []string
34	CanonicalPathFromRoot bool
35	Dir                   ModuleGenPath
36	SubDir                ModuleGenPath
37	OutTypeFlag           string
38	OutParams             []string
39	Deps                  Paths
40}
41
42type protoDependencyTag struct {
43	blueprint.BaseDependencyTag
44	name string
45}
46
47var ProtoPluginDepTag = protoDependencyTag{name: "plugin"}
48
49func ProtoDeps(ctx BottomUpMutatorContext, p *ProtoProperties) {
50	if String(p.Proto.Plugin) != "" && String(p.Proto.Type) != "" {
51		ctx.ModuleErrorf("only one of proto.type and proto.plugin can be specified.")
52	}
53
54	if plugin := String(p.Proto.Plugin); plugin != "" {
55		ctx.AddFarVariationDependencies([]blueprint.Variation{
56			{Mutator: "arch", Variation: ctx.Config().BuildOsVariant},
57		}, ProtoPluginDepTag, "protoc-gen-"+plugin)
58	}
59}
60
61func GetProtoFlags(ctx ModuleContext, p *ProtoProperties) ProtoFlags {
62	var flags []string
63	var deps Paths
64
65	if len(p.Proto.Local_include_dirs) > 0 {
66		localProtoIncludeDirs := PathsForModuleSrc(ctx, p.Proto.Local_include_dirs)
67		flags = append(flags, JoinWithPrefix(localProtoIncludeDirs.Strings(), "-I"))
68	}
69	if len(p.Proto.Include_dirs) > 0 {
70		rootProtoIncludeDirs := PathsForSource(ctx, p.Proto.Include_dirs)
71		flags = append(flags, JoinWithPrefix(rootProtoIncludeDirs.Strings(), "-I"))
72	}
73
74	ctx.VisitDirectDepsWithTag(ProtoPluginDepTag, func(dep Module) {
75		if hostTool, ok := dep.(HostToolProvider); !ok || !hostTool.HostToolPath().Valid() {
76			ctx.PropertyErrorf("proto.plugin", "module %q is not a host tool provider",
77				ctx.OtherModuleName(dep))
78		} else {
79			plugin := String(p.Proto.Plugin)
80			deps = append(deps, hostTool.HostToolPath().Path())
81			flags = append(flags, "--plugin=protoc-gen-"+plugin+"="+hostTool.HostToolPath().String())
82		}
83	})
84
85	var protoOutFlag string
86	if plugin := String(p.Proto.Plugin); plugin != "" {
87		protoOutFlag = "--" + plugin + "_out"
88	}
89
90	return ProtoFlags{
91		Flags:                 flags,
92		Deps:                  deps,
93		OutTypeFlag:           protoOutFlag,
94		CanonicalPathFromRoot: proptools.BoolDefault(p.Proto.Canonical_path_from_root, true),
95		Dir:                   PathForModuleGen(ctx, "proto"),
96		SubDir:                PathForModuleGen(ctx, "proto", ctx.ModuleDir()),
97	}
98}
99
100type ProtoProperties struct {
101	Proto struct {
102		// Proto generator type.  C++: full or lite.  Java: micro, nano, stream, or lite.
103		Type *string `android:"arch_variant"`
104
105		// Proto plugin to use as the generator.  Must be a cc_binary_host module.
106		Plugin *string `android:"arch_variant"`
107
108		// list of directories that will be added to the protoc include paths.
109		Include_dirs []string
110
111		// list of directories relative to the bp file that will
112		// be added to the protoc include paths.
113		Local_include_dirs []string
114
115		// whether to identify the proto files from the root of the
116		// source tree (the original method in Android, useful for
117		// android-specific protos), or relative from where they were
118		// specified (useful for external/third party protos).
119		//
120		// This defaults to true today, but is expected to default to
121		// false in the future.
122		Canonical_path_from_root *bool
123	} `android:"arch_variant"`
124}
125
126func ProtoRule(ctx ModuleContext, rule *RuleBuilder, protoFile Path, flags ProtoFlags, deps Paths,
127	outDir WritablePath, depFile WritablePath, outputs WritablePaths) {
128
129	var protoBase string
130	if flags.CanonicalPathFromRoot {
131		protoBase = "."
132	} else {
133		rel := protoFile.Rel()
134		protoBase = strings.TrimSuffix(protoFile.String(), rel)
135	}
136
137	rule.Command().
138		Tool(ctx.Config().HostToolPath(ctx, "aprotoc")).
139		FlagWithArg(flags.OutTypeFlag+"=", strings.Join(flags.OutParams, ",")+":"+outDir.String()).
140		FlagWithDepFile("--dependency_out=", depFile).
141		FlagWithArg("-I ", protoBase).
142		Flags(flags.Flags).
143		Input(protoFile).
144		Implicits(deps).
145		ImplicitOutputs(outputs)
146
147	rule.Command().
148		Tool(ctx.Config().HostToolPath(ctx, "dep_fixer")).Flag(depFile.String())
149}
150