objective_c_plugin.cc 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*
  2. *
  3. * Copyright 2015 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. // Generates Objective C gRPC service interface out of Protobuf IDL.
  19. #include <memory>
  20. #include "src/compiler/config.h"
  21. #include "src/compiler/objective_c_generator.h"
  22. #include "src/compiler/objective_c_generator_helpers.h"
  23. #include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
  24. using ::google::protobuf::compiler::objectivec::
  25. IsProtobufLibraryBundledProtoFile;
  26. using ::google::protobuf::compiler::objectivec::ProtobufLibraryFrameworkName;
  27. using ::grpc_objective_c_generator::FrameworkImport;
  28. using ::grpc_objective_c_generator::LocalImport;
  29. using ::grpc_objective_c_generator::PreprocIfElse;
  30. using ::grpc_objective_c_generator::PreprocIfNot;
  31. using ::grpc_objective_c_generator::SystemImport;
  32. namespace {
  33. inline ::grpc::string ImportProtoHeaders(
  34. const grpc::protobuf::FileDescriptor* dep, const char* indent,
  35. const ::grpc::string& framework) {
  36. ::grpc::string header = grpc_objective_c_generator::MessageHeaderName(dep);
  37. if (!IsProtobufLibraryBundledProtoFile(dep)) {
  38. if (framework.empty()) {
  39. return indent + LocalImport(header);
  40. } else {
  41. return indent + FrameworkImport(header, framework);
  42. }
  43. }
  44. ::grpc::string base_name = header;
  45. grpc_generator::StripPrefix(&base_name, "google/protobuf/");
  46. // create the import code snippet
  47. ::grpc::string framework_header =
  48. ::grpc::string(ProtobufLibraryFrameworkName) + "/" + base_name;
  49. static const ::grpc::string kFrameworkImportsCondition =
  50. "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS";
  51. return PreprocIfElse(kFrameworkImportsCondition,
  52. indent + SystemImport(framework_header),
  53. indent + LocalImport(header));
  54. }
  55. } // namespace
  56. class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
  57. public:
  58. ObjectiveCGrpcGenerator() {}
  59. virtual ~ObjectiveCGrpcGenerator() {}
  60. public:
  61. virtual bool Generate(const grpc::protobuf::FileDescriptor* file,
  62. const ::grpc::string& parameter,
  63. grpc::protobuf::compiler::GeneratorContext* context,
  64. ::grpc::string* error) const {
  65. if (file->service_count() == 0) {
  66. // No services. Do nothing.
  67. return true;
  68. }
  69. ::grpc::string framework;
  70. std::vector<::grpc::string> params_list =
  71. grpc_generator::tokenize(parameter, ",");
  72. for (auto param_str = params_list.begin(); param_str != params_list.end();
  73. ++param_str) {
  74. std::vector<::grpc::string> param =
  75. grpc_generator::tokenize(*param_str, "=");
  76. if (param[0] == "generate_for_named_framework") {
  77. if (param.size() != 2) {
  78. *error =
  79. grpc::string("Format: generate_for_named_framework=<Framework>");
  80. return false;
  81. } else if (param[1].empty()) {
  82. *error = grpc::string(
  83. "Name of framework cannot be empty for parameter: ") +
  84. param[0];
  85. return false;
  86. }
  87. framework = param[1];
  88. }
  89. }
  90. static const ::grpc::string kNonNullBegin = "NS_ASSUME_NONNULL_BEGIN\n";
  91. static const ::grpc::string kNonNullEnd = "NS_ASSUME_NONNULL_END\n";
  92. static const ::grpc::string kProtocolOnly = "GPB_GRPC_PROTOCOL_ONLY";
  93. static const ::grpc::string kForwardDeclare =
  94. "GPB_GRPC_FORWARD_DECLARE_MESSAGE_PROTO";
  95. ::grpc::string file_name =
  96. google::protobuf::compiler::objectivec::FilePath(file);
  97. grpc_objective_c_generator::Parameters generator_params;
  98. generator_params.no_v1_compatibility = false;
  99. if (!parameter.empty()) {
  100. std::vector<grpc::string> parameters_list =
  101. grpc_generator::tokenize(parameter, ",");
  102. for (auto parameter_string = parameters_list.begin();
  103. parameter_string != parameters_list.end(); parameter_string++) {
  104. std::vector<grpc::string> param =
  105. grpc_generator::tokenize(*parameter_string, "=");
  106. if (param[0] == "no_v1_compatibility") {
  107. generator_params.no_v1_compatibility = true;
  108. }
  109. }
  110. }
  111. {
  112. // Generate .pbrpc.h
  113. ::grpc::string imports;
  114. if (framework.empty()) {
  115. imports = LocalImport(file_name + ".pbobjc.h");
  116. } else {
  117. imports = FrameworkImport(file_name + ".pbobjc.h", framework);
  118. }
  119. ::grpc::string system_imports =
  120. SystemImport("ProtoRPC/ProtoService.h") +
  121. (generator_params.no_v1_compatibility
  122. ? SystemImport("ProtoRPC/ProtoRPC.h")
  123. : SystemImport("ProtoRPC/ProtoRPCLegacy.h"));
  124. if (!generator_params.no_v1_compatibility) {
  125. system_imports += SystemImport("RxLibrary/GRXWriteable.h") +
  126. SystemImport("RxLibrary/GRXWriter.h");
  127. }
  128. ::grpc::string forward_declarations =
  129. "@class GRPCUnaryProtoCall;\n"
  130. "@class GRPCStreamingProtoCall;\n"
  131. "@class GRPCCallOptions;\n"
  132. "@protocol GRPCProtoResponseHandler;\n";
  133. if (!generator_params.no_v1_compatibility) {
  134. forward_declarations += "@class GRPCProtoCall;\n";
  135. }
  136. forward_declarations += "\n";
  137. ::grpc::string class_declarations =
  138. grpc_objective_c_generator::GetAllMessageClasses(file);
  139. ::grpc::string class_imports;
  140. for (int i = 0; i < file->dependency_count(); i++) {
  141. class_imports +=
  142. ImportProtoHeaders(file->dependency(i), " ", framework);
  143. }
  144. ::grpc::string ng_protocols;
  145. for (int i = 0; i < file->service_count(); i++) {
  146. const grpc::protobuf::ServiceDescriptor* service = file->service(i);
  147. ng_protocols += grpc_objective_c_generator::GetV2Protocol(service);
  148. }
  149. ::grpc::string protocols;
  150. for (int i = 0; i < file->service_count(); i++) {
  151. const grpc::protobuf::ServiceDescriptor* service = file->service(i);
  152. protocols +=
  153. grpc_objective_c_generator::GetProtocol(service, generator_params);
  154. }
  155. ::grpc::string interfaces;
  156. for (int i = 0; i < file->service_count(); i++) {
  157. const grpc::protobuf::ServiceDescriptor* service = file->service(i);
  158. interfaces +=
  159. grpc_objective_c_generator::GetInterface(service, generator_params);
  160. }
  161. Write(context, file_name + ".pbrpc.h",
  162. PreprocIfNot(kForwardDeclare, imports) + "\n" +
  163. PreprocIfNot(kProtocolOnly, system_imports) + "\n" +
  164. class_declarations + "\n" +
  165. PreprocIfNot(kForwardDeclare, class_imports) + "\n" +
  166. forward_declarations + "\n" + kNonNullBegin + "\n" +
  167. ng_protocols + protocols + "\n" +
  168. PreprocIfNot(kProtocolOnly, interfaces) + "\n" + kNonNullEnd +
  169. "\n");
  170. }
  171. {
  172. // Generate .pbrpc.m
  173. ::grpc::string imports;
  174. if (framework.empty()) {
  175. imports = LocalImport(file_name + ".pbrpc.h") +
  176. LocalImport(file_name + ".pbobjc.h");
  177. } else {
  178. imports = FrameworkImport(file_name + ".pbrpc.h", framework) +
  179. FrameworkImport(file_name + ".pbobjc.h", framework);
  180. }
  181. imports += (generator_params.no_v1_compatibility
  182. ? SystemImport("ProtoRPC/ProtoRPC.h")
  183. : SystemImport("ProtoRPC/ProtoRPCLegacy.h"));
  184. if (!generator_params.no_v1_compatibility) {
  185. imports += SystemImport("RxLibrary/GRXWriter+Immediate.h");
  186. }
  187. ::grpc::string class_imports;
  188. for (int i = 0; i < file->dependency_count(); i++) {
  189. class_imports += ImportProtoHeaders(file->dependency(i), "", framework);
  190. }
  191. ::grpc::string definitions;
  192. for (int i = 0; i < file->service_count(); i++) {
  193. const grpc::protobuf::ServiceDescriptor* service = file->service(i);
  194. definitions +=
  195. grpc_objective_c_generator::GetSource(service, generator_params);
  196. }
  197. Write(context, file_name + ".pbrpc.m",
  198. PreprocIfNot(kProtocolOnly,
  199. imports + "\n" + class_imports + "\n" + definitions));
  200. }
  201. return true;
  202. }
  203. private:
  204. // Write the given code into the given file.
  205. void Write(grpc::protobuf::compiler::GeneratorContext* context,
  206. const ::grpc::string& filename, const ::grpc::string& code) const {
  207. std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
  208. context->Open(filename));
  209. grpc::protobuf::io::CodedOutputStream coded_out(output.get());
  210. coded_out.WriteRaw(code.data(), code.size());
  211. }
  212. };
  213. int main(int argc, char* argv[]) {
  214. ObjectiveCGrpcGenerator generator;
  215. return grpc::protobuf::compiler::PluginMain(argc, argv, &generator);
  216. }