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
19 // Generates Objective C gRPC service interface out of Protobuf IDL.
20
21 #include <memory>
22
23 #include "src/compiler/config.h"
24 #include "src/compiler/objective_c_generator.h"
25 #include "src/compiler/objective_c_generator_helpers.h"
26
27 #include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
28
29 using ::google::protobuf::compiler::objectivec::
30 IsProtobufLibraryBundledProtoFile;
31 using ::google::protobuf::compiler::objectivec::ProtobufLibraryFrameworkName;
32 using ::grpc_objective_c_generator::LocalImport;
33 using ::grpc_objective_c_generator::PreprocIfElse;
34 using ::grpc_objective_c_generator::PreprocIfNot;
35 using ::grpc_objective_c_generator::SystemImport;
36
37 namespace {
38
ImportProtoHeaders(const grpc::protobuf::FileDescriptor * dep,const char * indent)39 inline ::grpc::string ImportProtoHeaders(
40 const grpc::protobuf::FileDescriptor* dep, const char* indent) {
41 ::grpc::string header = grpc_objective_c_generator::MessageHeaderName(dep);
42
43 if (!IsProtobufLibraryBundledProtoFile(dep)) {
44 return indent + LocalImport(header);
45 }
46
47 ::grpc::string base_name = header;
48 grpc_generator::StripPrefix(&base_name, "google/protobuf/");
49 // create the import code snippet
50 ::grpc::string framework_header =
51 ::grpc::string(ProtobufLibraryFrameworkName) + "/" + base_name;
52
53 static const ::grpc::string kFrameworkImportsCondition =
54 "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS";
55 return PreprocIfElse(kFrameworkImportsCondition,
56 indent + SystemImport(framework_header),
57 indent + LocalImport(header));
58 }
59
60 } // namespace
61
62 class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
63 public:
ObjectiveCGrpcGenerator()64 ObjectiveCGrpcGenerator() {}
~ObjectiveCGrpcGenerator()65 virtual ~ObjectiveCGrpcGenerator() {}
66
67 public:
Generate(const grpc::protobuf::FileDescriptor * file,const::grpc::string & parameter,grpc::protobuf::compiler::GeneratorContext * context,::grpc::string * error) const68 virtual bool Generate(const grpc::protobuf::FileDescriptor* file,
69 const ::grpc::string& parameter,
70 grpc::protobuf::compiler::GeneratorContext* context,
71 ::grpc::string* error) const {
72 if (file->service_count() == 0) {
73 // No services. Do nothing.
74 return true;
75 }
76
77 static const ::grpc::string kNonNullBegin = "NS_ASSUME_NONNULL_BEGIN\n";
78 static const ::grpc::string kNonNullEnd = "NS_ASSUME_NONNULL_END\n";
79 static const ::grpc::string kProtocolOnly = "GPB_GRPC_PROTOCOL_ONLY";
80 static const ::grpc::string kForwardDeclare =
81 "GPB_GRPC_FORWARD_DECLARE_MESSAGE_PROTO";
82
83 ::grpc::string file_name =
84 google::protobuf::compiler::objectivec::FilePath(file);
85
86 {
87 // Generate .pbrpc.h
88
89 ::grpc::string imports = LocalImport(file_name + ".pbobjc.h");
90
91 ::grpc::string system_imports = SystemImport("ProtoRPC/ProtoService.h") +
92 SystemImport("ProtoRPC/ProtoRPC.h") +
93 SystemImport("RxLibrary/GRXWriteable.h") +
94 SystemImport("RxLibrary/GRXWriter.h");
95
96 ::grpc::string forward_declarations = "@class GRPCProtoCall;\n\n";
97
98 ::grpc::string class_declarations =
99 grpc_objective_c_generator::GetAllMessageClasses(file);
100
101 ::grpc::string class_imports;
102 for (int i = 0; i < file->dependency_count(); i++) {
103 class_imports += ImportProtoHeaders(file->dependency(i), " ");
104 }
105
106 ::grpc::string protocols;
107 for (int i = 0; i < file->service_count(); i++) {
108 const grpc::protobuf::ServiceDescriptor* service = file->service(i);
109 protocols += grpc_objective_c_generator::GetProtocol(service);
110 }
111
112 ::grpc::string interfaces;
113 for (int i = 0; i < file->service_count(); i++) {
114 const grpc::protobuf::ServiceDescriptor* service = file->service(i);
115 interfaces += grpc_objective_c_generator::GetInterface(service);
116 }
117
118 Write(context, file_name + ".pbrpc.h",
119 PreprocIfNot(kForwardDeclare, imports) + "\n" +
120 PreprocIfNot(kProtocolOnly, system_imports) + "\n" +
121 class_declarations + "\n" +
122 PreprocIfNot(kForwardDeclare, class_imports) + "\n" +
123 forward_declarations + "\n" + kNonNullBegin + "\n" + protocols +
124 "\n" + PreprocIfNot(kProtocolOnly, interfaces) + "\n" +
125 kNonNullEnd + "\n");
126 }
127
128 {
129 // Generate .pbrpc.m
130
131 ::grpc::string imports = LocalImport(file_name + ".pbrpc.h") +
132 LocalImport(file_name + ".pbobjc.h") +
133 SystemImport("ProtoRPC/ProtoRPC.h") +
134 SystemImport("RxLibrary/GRXWriter+Immediate.h");
135
136 ::grpc::string class_imports;
137 for (int i = 0; i < file->dependency_count(); i++) {
138 class_imports += ImportProtoHeaders(file->dependency(i), "");
139 }
140
141 ::grpc::string definitions;
142 for (int i = 0; i < file->service_count(); i++) {
143 const grpc::protobuf::ServiceDescriptor* service = file->service(i);
144 definitions += grpc_objective_c_generator::GetSource(service);
145 }
146
147 Write(context, file_name + ".pbrpc.m",
148 PreprocIfNot(kProtocolOnly,
149 imports + "\n" + class_imports + "\n" + definitions));
150 }
151
152 return true;
153 }
154
155 private:
156 // Write the given code into the given file.
Write(grpc::protobuf::compiler::GeneratorContext * context,const::grpc::string & filename,const::grpc::string & code) const157 void Write(grpc::protobuf::compiler::GeneratorContext* context,
158 const ::grpc::string& filename, const ::grpc::string& code) const {
159 std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
160 context->Open(filename));
161 grpc::protobuf::io::CodedOutputStream coded_out(output.get());
162 coded_out.WriteRaw(code.data(), code.size());
163 }
164 };
165
main(int argc,char * argv[])166 int main(int argc, char* argv[]) {
167 ObjectiveCGrpcGenerator generator;
168 return grpc::protobuf::compiler::PluginMain(argc, argv, &generator);
169 }
170