protobuf.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Copyright 2020 The Android Open Source Project
  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 rust
  15. import (
  16. "fmt"
  17. "strings"
  18. "android/soong/android"
  19. )
  20. var (
  21. defaultProtobufFlags = []string{""}
  22. )
  23. const (
  24. grpcSuffix = "_grpc"
  25. )
  26. type PluginType int
  27. const (
  28. Protobuf PluginType = iota
  29. Grpc
  30. )
  31. func init() {
  32. android.RegisterModuleType("rust_protobuf", RustProtobufFactory)
  33. android.RegisterModuleType("rust_protobuf_host", RustProtobufHostFactory)
  34. android.RegisterModuleType("rust_grpcio", RustGrpcioFactory)
  35. android.RegisterModuleType("rust_grpcio_host", RustGrpcioHostFactory)
  36. }
  37. var _ SourceProvider = (*protobufDecorator)(nil)
  38. type ProtobufProperties struct {
  39. // Path to the proto file that will be used to generate the source
  40. Proto *string `android:"path,arch_variant"`
  41. // List of additional flags to pass to aprotoc
  42. Proto_flags []string `android:"arch_variant"`
  43. // List of libraries which export include paths required for this module
  44. Header_libs []string `android:"arch_variant,variant_prepend"`
  45. }
  46. type protobufDecorator struct {
  47. *BaseSourceProvider
  48. Properties ProtobufProperties
  49. plugin PluginType
  50. }
  51. func (proto *protobufDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path {
  52. var protoFlags android.ProtoFlags
  53. var pluginPaths android.Paths
  54. protoFlags.OutTypeFlag = "--rust_out"
  55. outDir := android.PathForModuleOut(ctx)
  56. pluginPaths, protoFlags = proto.setupPlugin(ctx, protoFlags, outDir)
  57. protoFlags.Flags = append(protoFlags.Flags, defaultProtobufFlags...)
  58. protoFlags.Flags = append(protoFlags.Flags, proto.Properties.Proto_flags...)
  59. protoFlags.Deps = append(protoFlags.Deps, pluginPaths...)
  60. protoFile := android.OptionalPathForModuleSrc(ctx, proto.Properties.Proto)
  61. if !protoFile.Valid() {
  62. ctx.PropertyErrorf("proto", "invalid path to proto file")
  63. }
  64. // Add exported dependency include paths
  65. for _, include := range deps.depIncludePaths {
  66. protoFlags.Flags = append(protoFlags.Flags, "-I"+include.String())
  67. }
  68. stem := proto.BaseSourceProvider.getStem(ctx)
  69. // rust protobuf-codegen output <stem>.rs
  70. stemFile := android.PathForModuleOut(ctx, stem+".rs")
  71. // add mod_<stem>.rs to import <stem>.rs
  72. modFile := android.PathForModuleOut(ctx, "mod_"+stem+".rs")
  73. // mod_<stem>.rs is the main/first output file to be included/compiled
  74. outputs := android.WritablePaths{modFile, stemFile}
  75. if proto.plugin == Grpc {
  76. outputs = append(outputs, android.PathForModuleOut(ctx, stem+grpcSuffix+".rs"))
  77. }
  78. depFile := android.PathForModuleOut(ctx, "mod_"+stem+".d")
  79. rule := android.NewRuleBuilder()
  80. android.ProtoRule(ctx, rule, protoFile.Path(), protoFlags, protoFlags.Deps, outDir, depFile, outputs)
  81. rule.Command().Text("printf '" + proto.getModFileContents(ctx) + "' >").Output(modFile)
  82. rule.Build(pctx, ctx, "protoc_"+protoFile.Path().Rel(), "protoc "+protoFile.Path().Rel())
  83. proto.BaseSourceProvider.OutputFiles = android.Paths{modFile, stemFile}
  84. return modFile
  85. }
  86. func (proto *protobufDecorator) getModFileContents(ctx ModuleContext) string {
  87. stem := proto.BaseSourceProvider.getStem(ctx)
  88. lines := []string{
  89. "// @generated",
  90. fmt.Sprintf("pub mod %s;", stem),
  91. }
  92. if proto.plugin == Grpc {
  93. lines = append(lines, fmt.Sprintf("pub mod %s%s;", stem, grpcSuffix))
  94. lines = append(
  95. lines,
  96. "pub mod empty {",
  97. " pub use protobuf::well_known_types::Empty;",
  98. "}")
  99. }
  100. return strings.Join(lines, "\\n")
  101. }
  102. func (proto *protobufDecorator) setupPlugin(ctx ModuleContext, protoFlags android.ProtoFlags, outDir android.ModuleOutPath) (android.Paths, android.ProtoFlags) {
  103. pluginPaths := []android.Path{}
  104. if proto.plugin == Protobuf {
  105. pluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust")
  106. pluginPaths = append(pluginPaths, pluginPath)
  107. protoFlags.Flags = append(protoFlags.Flags, "--plugin="+pluginPath.String())
  108. } else if proto.plugin == Grpc {
  109. grpcPath := ctx.Config().HostToolPath(ctx, "grpc_rust_plugin")
  110. protobufPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust")
  111. pluginPaths = append(pluginPaths, grpcPath, protobufPath)
  112. protoFlags.Flags = append(protoFlags.Flags, "--grpc_out="+outDir.String())
  113. protoFlags.Flags = append(protoFlags.Flags, "--plugin=protoc-gen-grpc="+grpcPath.String())
  114. protoFlags.Flags = append(protoFlags.Flags, "--plugin=protoc-gen-rust="+protobufPath.String())
  115. } else {
  116. ctx.ModuleErrorf("Unknown protobuf plugin type requested")
  117. }
  118. return pluginPaths, protoFlags
  119. }
  120. func (proto *protobufDecorator) SourceProviderProps() []interface{} {
  121. return append(proto.BaseSourceProvider.SourceProviderProps(), &proto.Properties)
  122. }
  123. func (proto *protobufDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps {
  124. deps = proto.BaseSourceProvider.SourceProviderDeps(ctx, deps)
  125. deps.Rustlibs = append(deps.Rustlibs, "libprotobuf")
  126. deps.HeaderLibs = append(deps.SharedLibs, proto.Properties.Header_libs...)
  127. if proto.plugin == Grpc {
  128. deps.Rustlibs = append(deps.Rustlibs, "libgrpcio", "libfutures")
  129. deps.HeaderLibs = append(deps.HeaderLibs, "libprotobuf-cpp-full")
  130. }
  131. return deps
  132. }
  133. // rust_protobuf generates protobuf rust code from the provided proto file. This uses the protoc-gen-rust plugin for
  134. // protoc. Additional flags to the protoc command can be passed via the proto_flags property. This module type will
  135. // create library variants that can be used as a crate dependency by adding it to the rlibs, dylibs, and rustlibs
  136. // properties of other modules.
  137. func RustProtobufFactory() android.Module {
  138. module, _ := NewRustProtobuf(android.HostAndDeviceSupported)
  139. return module.Init()
  140. }
  141. // A host-only variant of rust_protobuf. Refer to rust_protobuf for more details.
  142. func RustProtobufHostFactory() android.Module {
  143. module, _ := NewRustProtobuf(android.HostSupported)
  144. return module.Init()
  145. }
  146. func RustGrpcioFactory() android.Module {
  147. module, _ := NewRustGrpcio(android.HostAndDeviceSupported)
  148. return module.Init()
  149. }
  150. // A host-only variant of rust_protobuf. Refer to rust_protobuf for more details.
  151. func RustGrpcioHostFactory() android.Module {
  152. module, _ := NewRustGrpcio(android.HostSupported)
  153. return module.Init()
  154. }
  155. func NewRustProtobuf(hod android.HostOrDeviceSupported) (*Module, *protobufDecorator) {
  156. protobuf := &protobufDecorator{
  157. BaseSourceProvider: NewSourceProvider(),
  158. Properties: ProtobufProperties{},
  159. plugin: Protobuf,
  160. }
  161. module := NewSourceProviderModule(hod, protobuf, false)
  162. return module, protobuf
  163. }
  164. func NewRustGrpcio(hod android.HostOrDeviceSupported) (*Module, *protobufDecorator) {
  165. protobuf := &protobufDecorator{
  166. BaseSourceProvider: NewSourceProvider(),
  167. Properties: ProtobufProperties{},
  168. plugin: Grpc,
  169. }
  170. module := NewSourceProviderModule(hod, protobuf, false)
  171. return module, protobuf
  172. }