proto.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  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. package android
  15. import (
  16. "strings"
  17. "android/soong/bazel"
  18. "github.com/google/blueprint"
  19. "github.com/google/blueprint/proptools"
  20. )
  21. const (
  22. canonicalPathFromRootDefault = true
  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. type ProtoFlags struct {
  32. Flags []string
  33. CanonicalPathFromRoot bool
  34. Dir ModuleGenPath
  35. SubDir ModuleGenPath
  36. OutTypeFlag string
  37. OutParams []string
  38. Deps Paths
  39. }
  40. type protoDependencyTag struct {
  41. blueprint.BaseDependencyTag
  42. name string
  43. }
  44. var ProtoPluginDepTag = protoDependencyTag{name: "plugin"}
  45. func ProtoDeps(ctx BottomUpMutatorContext, p *ProtoProperties) {
  46. if String(p.Proto.Plugin) != "" && String(p.Proto.Type) != "" {
  47. ctx.ModuleErrorf("only one of proto.type and proto.plugin can be specified.")
  48. }
  49. if plugin := String(p.Proto.Plugin); plugin != "" {
  50. ctx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(),
  51. ProtoPluginDepTag, "protoc-gen-"+plugin)
  52. }
  53. }
  54. func GetProtoFlags(ctx ModuleContext, p *ProtoProperties) ProtoFlags {
  55. var flags []string
  56. var deps Paths
  57. if len(p.Proto.Local_include_dirs) > 0 {
  58. localProtoIncludeDirs := PathsForModuleSrc(ctx, p.Proto.Local_include_dirs)
  59. flags = append(flags, JoinWithPrefix(localProtoIncludeDirs.Strings(), "-I"))
  60. }
  61. if len(p.Proto.Include_dirs) > 0 {
  62. rootProtoIncludeDirs := PathsForSource(ctx, p.Proto.Include_dirs)
  63. flags = append(flags, JoinWithPrefix(rootProtoIncludeDirs.Strings(), "-I"))
  64. }
  65. ctx.VisitDirectDepsWithTag(ProtoPluginDepTag, func(dep Module) {
  66. if hostTool, ok := dep.(HostToolProvider); !ok || !hostTool.HostToolPath().Valid() {
  67. ctx.PropertyErrorf("proto.plugin", "module %q is not a host tool provider",
  68. ctx.OtherModuleName(dep))
  69. } else {
  70. plugin := String(p.Proto.Plugin)
  71. deps = append(deps, hostTool.HostToolPath().Path())
  72. flags = append(flags, "--plugin=protoc-gen-"+plugin+"="+hostTool.HostToolPath().String())
  73. }
  74. })
  75. var protoOutFlag string
  76. if plugin := String(p.Proto.Plugin); plugin != "" {
  77. protoOutFlag = "--" + plugin + "_out"
  78. }
  79. return ProtoFlags{
  80. Flags: flags,
  81. Deps: deps,
  82. OutTypeFlag: protoOutFlag,
  83. CanonicalPathFromRoot: proptools.BoolDefault(p.Proto.Canonical_path_from_root, canonicalPathFromRootDefault),
  84. Dir: PathForModuleGen(ctx, "proto"),
  85. SubDir: PathForModuleGen(ctx, "proto", ctx.ModuleDir()),
  86. }
  87. }
  88. type ProtoProperties struct {
  89. Proto struct {
  90. // Proto generator type. C++: full or lite. Java: micro, nano, stream, or lite.
  91. Type *string `android:"arch_variant"`
  92. // Proto plugin to use as the generator. Must be a cc_binary_host module.
  93. Plugin *string `android:"arch_variant"`
  94. // list of directories that will be added to the protoc include paths.
  95. Include_dirs []string
  96. // list of directories relative to the bp file that will
  97. // be added to the protoc include paths.
  98. Local_include_dirs []string
  99. // whether to identify the proto files from the root of the
  100. // source tree (the original method in Android, useful for
  101. // android-specific protos), or relative from where they were
  102. // specified (useful for external/third party protos).
  103. //
  104. // This defaults to true today, but is expected to default to
  105. // false in the future.
  106. Canonical_path_from_root *bool
  107. } `android:"arch_variant"`
  108. }
  109. func ProtoRule(rule *RuleBuilder, protoFile Path, flags ProtoFlags, deps Paths,
  110. outDir WritablePath, depFile WritablePath, outputs WritablePaths) {
  111. var protoBase string
  112. if flags.CanonicalPathFromRoot {
  113. protoBase = "."
  114. } else {
  115. rel := protoFile.Rel()
  116. protoBase = strings.TrimSuffix(protoFile.String(), rel)
  117. }
  118. rule.Command().
  119. BuiltTool("aprotoc").
  120. FlagWithArg(flags.OutTypeFlag+"=", strings.Join(flags.OutParams, ",")+":"+outDir.String()).
  121. FlagWithDepFile("--dependency_out=", depFile).
  122. FlagWithArg("-I ", protoBase).
  123. Flags(flags.Flags).
  124. Input(protoFile).
  125. Implicits(deps).
  126. ImplicitOutputs(outputs)
  127. rule.Command().
  128. BuiltTool("dep_fixer").Flag(depFile.String())
  129. }
  130. // Bp2buildProtoInfo contains information necessary to pass on to language specific conversion.
  131. type Bp2buildProtoInfo struct {
  132. Type *string
  133. Name string
  134. Proto_libs bazel.LabelList
  135. }
  136. type ProtoAttrs struct {
  137. Srcs bazel.LabelListAttribute
  138. Strip_import_prefix *string
  139. Deps bazel.LabelListAttribute
  140. }
  141. // For each package in the include_dirs property a proto_library target should
  142. // be added to the BUILD file in that package and a mapping should be added here
  143. var includeDirsToProtoDeps = map[string]string{
  144. "external/protobuf/src": "//external/protobuf:libprotobuf-proto",
  145. }
  146. // Bp2buildProtoProperties converts proto properties, creating a proto_library and returning the
  147. // information necessary for language-specific handling.
  148. func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, m *ModuleBase, srcs bazel.LabelListAttribute) (Bp2buildProtoInfo, bool) {
  149. var info Bp2buildProtoInfo
  150. if srcs.IsEmpty() {
  151. return info, false
  152. }
  153. var protoLibraries bazel.LabelList
  154. var directProtoSrcs bazel.LabelList
  155. // For filegroups that should be converted to proto_library just collect the
  156. // labels of converted proto_library targets.
  157. for _, protoSrc := range srcs.Value.Includes {
  158. src := protoSrc.OriginalModuleName
  159. if fg, ok := ToFileGroupAsLibrary(ctx, src); ok &&
  160. fg.ShouldConvertToProtoLibrary(ctx) {
  161. protoLibraries.Add(&bazel.Label{
  162. Label: fg.GetProtoLibraryLabel(ctx),
  163. })
  164. } else {
  165. directProtoSrcs.Add(&protoSrc)
  166. }
  167. }
  168. info.Name = m.Name() + "_proto"
  169. if len(directProtoSrcs.Includes) > 0 {
  170. attrs := ProtoAttrs{
  171. Srcs: bazel.MakeLabelListAttribute(directProtoSrcs),
  172. }
  173. attrs.Deps.Append(bazel.MakeLabelListAttribute(protoLibraries))
  174. for axis, configToProps := range m.GetArchVariantProperties(ctx, &ProtoProperties{}) {
  175. for _, rawProps := range configToProps {
  176. var props *ProtoProperties
  177. var ok bool
  178. if props, ok = rawProps.(*ProtoProperties); !ok {
  179. ctx.ModuleErrorf("Could not cast ProtoProperties to expected type")
  180. }
  181. if axis == bazel.NoConfigAxis {
  182. info.Type = props.Proto.Type
  183. if !proptools.BoolDefault(props.Proto.Canonical_path_from_root, canonicalPathFromRootDefault) {
  184. // an empty string indicates to strips the package path
  185. path := ""
  186. attrs.Strip_import_prefix = &path
  187. }
  188. for _, dir := range props.Proto.Include_dirs {
  189. if dep, ok := includeDirsToProtoDeps[dir]; ok {
  190. attrs.Deps.Add(bazel.MakeLabelAttribute(dep))
  191. } else {
  192. ctx.PropertyErrorf("Could not find the proto_library target for include dir", dir)
  193. }
  194. }
  195. } else if props.Proto.Type != info.Type && props.Proto.Type != nil {
  196. ctx.ModuleErrorf("Cannot handle arch-variant types for protos at this time.")
  197. }
  198. }
  199. }
  200. tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module())
  201. ctx.CreateBazelTargetModule(
  202. bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
  203. CommonAttributes{Name: info.Name, Tags: tags},
  204. &attrs,
  205. )
  206. protoLibraries.Add(&bazel.Label{
  207. Label: ":" + info.Name,
  208. })
  209. }
  210. info.Proto_libs = protoLibraries
  211. return info, true
  212. }