diff --git a/BUILD b/BUILD
index b69c9404113..b4b10b535e8 100644
--- a/BUILD
+++ b/BUILD
@@ -84,6 +84,7 @@ cc_library(
"src/core/lib/support/stack_lockfree.c",
"src/core/lib/support/string.c",
"src/core/lib/support/string_posix.c",
+ "src/core/lib/support/string_util_win32.c",
"src/core/lib/support/string_win32.c",
"src/core/lib/support/subprocess_posix.c",
"src/core/lib/support/subprocess_windows.c",
@@ -98,6 +99,7 @@ cc_library(
"src/core/lib/support/time_precise.c",
"src/core/lib/support/time_win32.c",
"src/core/lib/support/tls_pthread.c",
+ "src/core/lib/support/tmpfile_msys.c",
"src/core/lib/support/tmpfile_posix.c",
"src/core/lib/support/tmpfile_win32.c",
"src/core/lib/support/wrap_memcpy.c",
@@ -1219,6 +1221,7 @@ objc_library(
"src/core/lib/support/stack_lockfree.c",
"src/core/lib/support/string.c",
"src/core/lib/support/string_posix.c",
+ "src/core/lib/support/string_util_win32.c",
"src/core/lib/support/string_win32.c",
"src/core/lib/support/subprocess_posix.c",
"src/core/lib/support/subprocess_windows.c",
@@ -1233,6 +1236,7 @@ objc_library(
"src/core/lib/support/time_precise.c",
"src/core/lib/support/time_win32.c",
"src/core/lib/support/tls_pthread.c",
+ "src/core/lib/support/tmpfile_msys.c",
"src/core/lib/support/tmpfile_posix.c",
"src/core/lib/support/tmpfile_win32.c",
"src/core/lib/support/wrap_memcpy.c",
diff --git a/Makefile b/Makefile
index 3b7dbd9638a..922e0b0568f 100644
--- a/Makefile
+++ b/Makefile
@@ -1010,6 +1010,7 @@ cxx_time_test: $(BINDIR)/$(CONFIG)/cxx_time_test
end2end_test: $(BINDIR)/$(CONFIG)/end2end_test
generic_async_streaming_ping_pong_test: $(BINDIR)/$(CONFIG)/generic_async_streaming_ping_pong_test
generic_end2end_test: $(BINDIR)/$(CONFIG)/generic_end2end_test
+golden_file_test: $(BINDIR)/$(CONFIG)/golden_file_test
grpc_cli: $(BINDIR)/$(CONFIG)/grpc_cli
grpc_cpp_plugin: $(BINDIR)/$(CONFIG)/grpc_cpp_plugin
grpc_csharp_plugin: $(BINDIR)/$(CONFIG)/grpc_csharp_plugin
@@ -1381,6 +1382,7 @@ buildtests_cxx: buildtests_zookeeper privatelibs_cxx \
$(BINDIR)/$(CONFIG)/end2end_test \
$(BINDIR)/$(CONFIG)/generic_async_streaming_ping_pong_test \
$(BINDIR)/$(CONFIG)/generic_end2end_test \
+ $(BINDIR)/$(CONFIG)/golden_file_test \
$(BINDIR)/$(CONFIG)/grpc_cli \
$(BINDIR)/$(CONFIG)/grpclb_api_test \
$(BINDIR)/$(CONFIG)/hybrid_end2end_test \
@@ -1712,6 +1714,8 @@ test_cxx: test_zookeeper buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/generic_async_streaming_ping_pong_test || ( echo test generic_async_streaming_ping_pong_test failed ; exit 1 )
$(E) "[RUN] Testing generic_end2end_test"
$(Q) $(BINDIR)/$(CONFIG)/generic_end2end_test || ( echo test generic_end2end_test failed ; exit 1 )
+ $(E) "[RUN] Testing golden_file_test"
+ $(Q) $(BINDIR)/$(CONFIG)/golden_file_test || ( echo test golden_file_test failed ; exit 1 )
$(E) "[RUN] Testing grpclb_api_test"
$(Q) $(BINDIR)/$(CONFIG)/grpclb_api_test || ( echo test grpclb_api_test failed ; exit 1 )
$(E) "[RUN] Testing hybrid_end2end_test"
@@ -1880,6 +1884,21 @@ $(GENDIR)/src/proto/grpc/lb/v0/load_balancer.grpc.pb.cc: src/proto/grpc/lb/v0/lo
$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
endif
+ifeq ($(NO_PROTOC),true)
+$(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc: protoc_dep_error
+$(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc: protoc_dep_error
+else
+$(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc: src/proto/grpc/testing/compiler_test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+ $(E) "[PROTOC] Generating protobuf CC file from $<"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc: src/proto/grpc/testing/compiler_test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+ $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+endif
+
ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/control.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc: protoc_dep_error
@@ -2331,6 +2350,7 @@ LIBGPR_SRC = \
src/core/lib/support/stack_lockfree.c \
src/core/lib/support/string.c \
src/core/lib/support/string_posix.c \
+ src/core/lib/support/string_util_win32.c \
src/core/lib/support/string_win32.c \
src/core/lib/support/subprocess_posix.c \
src/core/lib/support/subprocess_windows.c \
@@ -2345,6 +2365,7 @@ LIBGPR_SRC = \
src/core/lib/support/time_precise.c \
src/core/lib/support/time_win32.c \
src/core/lib/support/tls_pthread.c \
+ src/core/lib/support/tmpfile_msys.c \
src/core/lib/support/tmpfile_posix.c \
src/core/lib/support/tmpfile_win32.c \
src/core/lib/support/wrap_memcpy.c \
@@ -10444,6 +10465,53 @@ endif
endif
+GOLDEN_FILE_TEST_SRC = \
+ $(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc $(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc \
+ test/cpp/codegen/golden_file_test.cc \
+
+GOLDEN_FILE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GOLDEN_FILE_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/golden_file_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/golden_file_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/golden_file_test: $(PROTOBUF_DEP) $(GOLDEN_FILE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LDXX) $(LDFLAGS) $(GOLDEN_FILE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/golden_file_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/compiler_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+$(OBJDIR)/$(CONFIG)/test/cpp/codegen/golden_file_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_golden_file_test: $(GOLDEN_FILE_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(GOLDEN_FILE_TEST_OBJS:.o=.dep)
+endif
+endif
+$(OBJDIR)/$(CONFIG)/test/cpp/codegen/golden_file_test.o: $(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc $(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc
+
+
GRPC_CLI_SRC = \
test/cpp/util/grpc_cli.cc \
diff --git a/binding.gyp b/binding.gyp
index 058743edbf8..4314ab7243d 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -522,6 +522,7 @@
'src/core/lib/support/stack_lockfree.c',
'src/core/lib/support/string.c',
'src/core/lib/support/string_posix.c',
+ 'src/core/lib/support/string_util_win32.c',
'src/core/lib/support/string_win32.c',
'src/core/lib/support/subprocess_posix.c',
'src/core/lib/support/subprocess_windows.c',
@@ -536,6 +537,7 @@
'src/core/lib/support/time_precise.c',
'src/core/lib/support/time_win32.c',
'src/core/lib/support/tls_pthread.c',
+ 'src/core/lib/support/tmpfile_msys.c',
'src/core/lib/support/tmpfile_posix.c',
'src/core/lib/support/tmpfile_win32.c',
'src/core/lib/support/wrap_memcpy.c',
diff --git a/build.yaml b/build.yaml
index 6c00b42a1e7..441752dc3dc 100644
--- a/build.yaml
+++ b/build.yaml
@@ -103,6 +103,7 @@ filegroups:
- src/core/lib/support/stack_lockfree.c
- src/core/lib/support/string.c
- src/core/lib/support/string_posix.c
+ - src/core/lib/support/string_util_win32.c
- src/core/lib/support/string_win32.c
- src/core/lib/support/subprocess_posix.c
- src/core/lib/support/subprocess_windows.c
@@ -117,6 +118,7 @@ filegroups:
- src/core/lib/support/time_precise.c
- src/core/lib/support/time_win32.c
- src/core/lib/support/tls_pthread.c
+ - src/core/lib/support/tmpfile_msys.c
- src/core/lib/support/tmpfile_posix.c
- src/core/lib/support/tmpfile_win32.c
- src/core/lib/support/wrap_memcpy.c
@@ -2551,6 +2553,17 @@ targets:
- grpc
- gpr_test_util
- gpr
+- name: golden_file_test
+ gtest: true
+ build: test
+ language: c++
+ src:
+ - src/proto/grpc/testing/compiler_test.proto
+ - test/cpp/codegen/golden_file_test.cc
+ deps:
+ - grpc++
+ - grpc
+ - gpr
- name: grpc_cli
build: test
run: false
diff --git a/config.m4 b/config.m4
index 2d930a648e1..74f9ad242ab 100644
--- a/config.m4
+++ b/config.m4
@@ -63,6 +63,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/support/stack_lockfree.c \
src/core/lib/support/string.c \
src/core/lib/support/string_posix.c \
+ src/core/lib/support/string_util_win32.c \
src/core/lib/support/string_win32.c \
src/core/lib/support/subprocess_posix.c \
src/core/lib/support/subprocess_windows.c \
@@ -77,6 +78,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/support/time_precise.c \
src/core/lib/support/time_win32.c \
src/core/lib/support/tls_pthread.c \
+ src/core/lib/support/tmpfile_msys.c \
src/core/lib/support/tmpfile_posix.c \
src/core/lib/support/tmpfile_win32.c \
src/core/lib/support/wrap_memcpy.c \
diff --git a/doc/fail_fast.md b/doc/fail_fast.md
new file mode 100644
index 00000000000..3ed4297194b
--- /dev/null
+++ b/doc/fail_fast.md
@@ -0,0 +1,15 @@
+gRPC Fail Fast Semantics
+========================
+
+Fail fast requests allow terminating requests (with status UNAVAILABLE) prior
+to the deadline of the request being met.
+
+gRPC implementations of fail fast can terminate requests whenever a channel is
+in the TRANSIENT_FAILURE or SHUTDOWN states. If the channel is in any other
+state (CONNECTING, READY, or IDLE) the request should not be terminated.
+
+Fail fast SHOULD be the default for gRPC implementations, with an option to
+switch to non fail fast.
+
+The opposite of fail fast is 'ignore connectivity'.
+
diff --git a/examples/cpp/helloworld/Makefile b/examples/cpp/helloworld/Makefile
index 4b1867e2920..470b83573e4 100644
--- a/examples/cpp/helloworld/Makefile
+++ b/examples/cpp/helloworld/Makefile
@@ -32,7 +32,7 @@
CXX = g++
CPPFLAGS += -I/usr/local/include -pthread
CXXFLAGS += -std=c++11
-LDFLAGS += -L/usr/local/lib -lgrpc++_unsecure -lgrpc -lprotobuf -lpthread -ldl
+LDFLAGS += -L/usr/local/lib `pkg-config --libs grpc++` -lprotobuf -lpthread -ldl
PROTOC = protoc
GRPC_CPP_PLUGIN = grpc_cpp_plugin
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
diff --git a/examples/cpp/route_guide/Makefile b/examples/cpp/route_guide/Makefile
index 0fbb0a89298..11f2a00cc89 100644
--- a/examples/cpp/route_guide/Makefile
+++ b/examples/cpp/route_guide/Makefile
@@ -32,7 +32,7 @@
CXX = g++
CPPFLAGS += -I/usr/local/include -pthread
CXXFLAGS += -std=c++11
-LDFLAGS += -L/usr/local/lib -lgrpc++_unsecure -lgrpc -lprotobuf -lpthread -ldl
+LDFLAGS += -L/usr/local/lib `pkg-config --libs grpc++` -lprotobuf -lpthread -ldl
PROTOC = protoc
GRPC_CPP_PLUGIN = grpc_cpp_plugin
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
diff --git a/examples/python/README.md b/examples/python/README.md
index b57da8f6428..9992baa8421 100644
--- a/examples/python/README.md
+++ b/examples/python/README.md
@@ -8,12 +8,19 @@ For this sample, we've already generated the server and client stubs from
Install gRPC:
- ```sh
+```sh
$ pip install grpcio
```
Or, to install it system wide:
```sh
- $ sudo pip install grpcio
+ $ sudo pip install grpcio
+```
+
+If you're on Windows, make sure you installed the `pip.exe` component when you
+installed Python. Invoke as above but with `pip.exe` instead of `pip` (you may
+also need to invoke from a `cmd.exe` ran as administrator):
+```sh
+ $ pip.exe install grpcio
```
Download the example
diff --git a/gRPC.podspec b/gRPC.podspec
index d66e03354bb..77d35bd2c79 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -144,6 +144,7 @@ Pod::Spec.new do |s|
'src/core/lib/support/stack_lockfree.c',
'src/core/lib/support/string.c',
'src/core/lib/support/string_posix.c',
+ 'src/core/lib/support/string_util_win32.c',
'src/core/lib/support/string_win32.c',
'src/core/lib/support/subprocess_posix.c',
'src/core/lib/support/subprocess_windows.c',
@@ -158,6 +159,7 @@ Pod::Spec.new do |s|
'src/core/lib/support/time_precise.c',
'src/core/lib/support/time_win32.c',
'src/core/lib/support/tls_pthread.c',
+ 'src/core/lib/support/tmpfile_msys.c',
'src/core/lib/support/tmpfile_posix.c',
'src/core/lib/support/tmpfile_win32.c',
'src/core/lib/support/wrap_memcpy.c',
diff --git a/grpc.def b/grpc.def
index 6542c06a4ba..61948ed1b89 100644
--- a/grpc.def
+++ b/grpc.def
@@ -86,6 +86,7 @@ EXPORTS
grpc_header_key_is_legal
grpc_header_nonbin_value_is_legal
grpc_is_binary_header
+ grpc_call_error_to_string
grpc_auth_property_iterator_next
grpc_auth_context_property_iterator
grpc_auth_context_peer_identity
diff --git a/grpc.gemspec b/grpc.gemspec
index a9f0f681df0..e68cd81da7a 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -124,6 +124,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/support/stack_lockfree.c )
s.files += %w( src/core/lib/support/string.c )
s.files += %w( src/core/lib/support/string_posix.c )
+ s.files += %w( src/core/lib/support/string_util_win32.c )
s.files += %w( src/core/lib/support/string_win32.c )
s.files += %w( src/core/lib/support/subprocess_posix.c )
s.files += %w( src/core/lib/support/subprocess_windows.c )
@@ -138,6 +139,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/support/time_precise.c )
s.files += %w( src/core/lib/support/time_win32.c )
s.files += %w( src/core/lib/support/tls_pthread.c )
+ s.files += %w( src/core/lib/support/tmpfile_msys.c )
s.files += %w( src/core/lib/support/tmpfile_posix.c )
s.files += %w( src/core/lib/support/tmpfile_win32.c )
s.files += %w( src/core/lib/support/wrap_memcpy.c )
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 5c868aece37..0ca28c0fef1 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -384,6 +384,9 @@ GRPCAPI int grpc_header_nonbin_value_is_legal(const char *value, size_t length);
/** Check whether a metadata key corresponds to a binary value */
GRPCAPI int grpc_is_binary_header(const char *key, size_t length);
+/** Convert grpc_call_error values to a string */
+GRPCAPI const char *grpc_call_error_to_string(grpc_call_error error);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/grpc/impl/codegen/port_platform.h b/include/grpc/impl/codegen/port_platform.h
index 3242f07599b..1229d488edb 100644
--- a/include/grpc/impl/codegen/port_platform.h
+++ b/include/grpc/impl/codegen/port_platform.h
@@ -82,28 +82,31 @@
things. */
#if !defined(GPR_NO_AUTODETECT_PLATFORM)
+#if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32)
#if defined(_WIN64) || defined(WIN64)
-#define GPR_PLATFORM_STRING "windows"
-#define GPR_WIN32 1
#define GPR_ARCH_64 1
-#define GPR_GETPID_IN_PROCESS_H 1
-#define GPR_WINSOCK_SOCKET 1
-#define GPR_WINDOWS_SUBPROCESS 1
-#ifdef __GNUC__
-#define GPR_GCC_ATOMIC 1
-#define GPR_GCC_TLS 1
#else
-#define GPR_WIN32_ATOMIC 1
-#define GPR_MSVC_TLS 1
+#define GPR_ARCH_32 1
#endif
-#define GPR_WINDOWS_CRASH_HANDLER 1
-#elif defined(_WIN32) || defined(WIN32)
#define GPR_PLATFORM_STRING "windows"
-#define GPR_ARCH_32 1
#define GPR_WIN32 1
-#define GPR_GETPID_IN_PROCESS_H 1
#define GPR_WINSOCK_SOCKET 1
#define GPR_WINDOWS_SUBPROCESS 1
+#define GPR_WIN32_ENV
+#ifdef __MSYS__
+#define GPR_GETPID_IN_UNISTD_H 1
+#define GPR_MSYS_TMPFILE
+#define GPR_POSIX_LOG
+#define GPR_POSIX_STRING
+#define GPR_POSIX_TIME
+#else
+#define GPR_GETPID_IN_PROCESS_H 1
+#define GPR_WIN32_TMPFILE
+#define GPR_WIN32_LOG
+#define GPR_WINDOWS_CRASH_HANDLER 1
+#define GPR_WIN32_STRING
+#define GPR_WIN32_TIME
+#endif
#ifdef __GNUC__
#define GPR_GCC_ATOMIC 1
#define GPR_GCC_TLS 1
@@ -111,7 +114,6 @@
#define GPR_WIN32_ATOMIC 1
#define GPR_MSVC_TLS 1
#endif
-#define GPR_WINDOWS_CRASH_HANDLER 1
#elif defined(ANDROID) || defined(__ANDROID__)
#define GPR_PLATFORM_STRING "android"
#define GPR_ANDROID 1
@@ -127,6 +129,8 @@
#define GPR_POSIX_SOCKETUTILS 1
#define GPR_POSIX_ENV 1
#define GPR_POSIX_FILE 1
+#define GPR_POSIX_TMPFILE 1
+#define GPR_POSIX_LOG
#define GPR_POSIX_STRING 1
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
@@ -153,6 +157,7 @@
#define GPR_GCC_ATOMIC 1
#define GPR_GCC_TLS 1
#define GPR_LINUX 1
+#define GPR_LINUX_LOG
#define GPR_LINUX_MULTIPOLL_WITH_EPOLL 1
#define GPR_POSIX_WAKEUP_FD 1
#define GPR_POSIX_SOCKET 1
@@ -176,6 +181,7 @@
#define GPR_POSIX_SOCKETUTILS
#endif
#define GPR_POSIX_FILE 1
+#define GPR_POSIX_TMPFILE 1
#define GPR_POSIX_STRING 1
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
@@ -214,6 +220,7 @@
#define GPR_POSIX_SOCKETUTILS 1
#define GPR_POSIX_ENV 1
#define GPR_POSIX_FILE 1
+#define GPR_POSIX_TMPFILE 1
#define GPR_POSIX_STRING 1
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
@@ -244,6 +251,7 @@
#define GPR_POSIX_SOCKETUTILS 1
#define GPR_POSIX_ENV 1
#define GPR_POSIX_FILE 1
+#define GPR_POSIX_TMPFILE 1
#define GPR_POSIX_STRING 1
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
@@ -281,6 +289,7 @@
#define GPR_POSIX_SOCKETUTILS 1
#define GPR_POSIX_ENV 1
#define GPR_POSIX_FILE 1
+#define GPR_POSIX_TMPFILE 1
#define GPR_POSIX_STRING 1
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
diff --git a/package.xml b/package.xml
index 3ae810df5eb..ffb1c56ed64 100644
--- a/package.xml
+++ b/package.xml
@@ -131,6 +131,7 @@
+
@@ -145,6 +146,7 @@
+
diff --git a/src/compiler/config.h b/src/compiler/config.h
index fea976c3181..d8b95818dbb 100644
--- a/src/compiler/config.h
+++ b/src/compiler/config.h
@@ -42,8 +42,10 @@
#include
#define GRPC_CUSTOM_DESCRIPTOR ::google::protobuf::Descriptor
#define GRPC_CUSTOM_FILEDESCRIPTOR ::google::protobuf::FileDescriptor
+#define GRPC_CUSTOM_FILEDESCRIPTORPROTO ::google::protobuf::FileDescriptorProto
#define GRPC_CUSTOM_METHODDESCRIPTOR ::google::protobuf::MethodDescriptor
#define GRPC_CUSTOM_SERVICEDESCRIPTOR ::google::protobuf::ServiceDescriptor
+#define GRPC_CUSTOM_SOURCELOCATION ::google::protobuf::SourceLocation
#endif
#ifndef GRPC_CUSTOM_CODEGENERATOR
@@ -68,12 +70,19 @@
#define GRPC_CUSTOM_PLUGINMAIN ::google::protobuf::compiler::PluginMain
#endif
+#ifndef GRPC_CUSTOM_PARSEGENERATORPARAMETER
+#include
+#define GRPC_CUSTOM_PARSEGENERATORPARAMETER ::google::protobuf::compiler::ParseGeneratorParameter
+#endif
+
namespace grpc {
namespace protobuf {
typedef GRPC_CUSTOM_DESCRIPTOR Descriptor;
typedef GRPC_CUSTOM_FILEDESCRIPTOR FileDescriptor;
+typedef GRPC_CUSTOM_FILEDESCRIPTORPROTO FileDescriptorProto;
typedef GRPC_CUSTOM_METHODDESCRIPTOR MethodDescriptor;
typedef GRPC_CUSTOM_SERVICEDESCRIPTOR ServiceDescriptor;
+typedef GRPC_CUSTOM_SOURCELOCATION SourceLocation;
namespace compiler {
typedef GRPC_CUSTOM_CODEGENERATOR CodeGenerator;
typedef GRPC_CUSTOM_GENERATORCONTEXT GeneratorContext;
@@ -81,6 +90,11 @@ static inline int PluginMain(int argc, char* argv[],
const CodeGenerator* generator) {
return GRPC_CUSTOM_PLUGINMAIN(argc, argv, generator);
}
+static inline void ParseGeneratorParameter(const string& parameter,
+ std::vector >* options) {
+ GRPC_CUSTOM_PARSEGENERATORPARAMETER(parameter, options);
+}
+
} // namespace compiler
namespace io {
typedef GRPC_CUSTOM_PRINTER Printer;
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index 9319c419349..e2f127094ad 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -102,6 +102,11 @@ grpc::string GetHeaderPrologue(File *file, const Parameters & /*params*/) {
printer->Print(vars,
"// If you make any local change, they will be lost.\n");
printer->Print(vars, "// source: $filename$\n");
+ grpc::string leading_comments = file->GetLeadingComments();
+ if (!leading_comments.empty()) {
+ printer->Print(vars, "// Original file comments:\n");
+ printer->Print(leading_comments.c_str());
+ }
printer->Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n");
printer->Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n");
printer->Print(vars, "\n");
@@ -456,6 +461,7 @@ void PrintHeaderServerMethodSync(Printer *printer, const Method *method,
(*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type_name();
(*vars)["Response"] = method->output_type_name();
+ printer->Print(method->GetLeadingComments().c_str());
if (method->NoStreaming()) {
printer->Print(*vars,
"virtual ::grpc::Status $Method$("
@@ -480,6 +486,7 @@ void PrintHeaderServerMethodSync(Printer *printer, const Method *method,
"::grpc::ServerReaderWriter< $Response$, $Request$>* stream);"
"\n");
}
+ printer->Print(method->GetTrailingComments().c_str());
}
void PrintHeaderServerMethodAsync(
@@ -674,6 +681,7 @@ void PrintHeaderService(Printer *printer,
std::map *vars) {
(*vars)["Service"] = service->name();
+ printer->Print(service->GetLeadingComments().c_str());
printer->Print(*vars,
"class $Service$ GRPC_FINAL {\n"
" public:\n");
@@ -686,7 +694,9 @@ void PrintHeaderService(Printer *printer,
printer->Indent();
printer->Print("virtual ~StubInterface() {}\n");
for (int i = 0; i < service->method_count(); ++i) {
+ printer->Print(service->method(i)->GetLeadingComments().c_str());
PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars, true);
+ printer->Print(service->method(i)->GetTrailingComments().c_str());
}
printer->Outdent();
printer->Print("private:\n");
@@ -762,6 +772,7 @@ void PrintHeaderService(Printer *printer,
printer->Outdent();
printer->Print("};\n");
+ printer->Print(service->GetTrailingComments().c_str());
}
grpc::string GetHeaderServices(File *file,
@@ -817,6 +828,8 @@ grpc::string GetHeaderEpilogue(File *file, const Parameters & /*params*/) {
printer->Print(vars, "\n");
printer->Print(vars, "#endif // GRPC_$filename_identifier$__INCLUDED\n");
+
+ printer->Print(file->GetTrailingComments().c_str());
}
return output;
}
@@ -837,6 +850,7 @@ grpc::string GetSourcePrologue(File *file, const Parameters & /*params*/) {
printer->Print(vars,
"// If you make any local change, they will be lost.\n");
printer->Print(vars, "// source: $filename$\n\n");
+
printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
printer->Print(vars, "#include \"$filename_base$$service_header_ext$\"\n");
printer->Print(vars, file->additional_headers().c_str());
diff --git a/src/compiler/cpp_generator.h b/src/compiler/cpp_generator.h
index 953ddfd569e..2a003b10695 100644
--- a/src/compiler/cpp_generator.h
+++ b/src/compiler/cpp_generator.h
@@ -64,8 +64,16 @@ struct Parameters {
grpc::string grpc_search_path;
};
+// A common interface for objects having comments in the source.
+// Return formatted comments to be inserted in generated code.
+struct CommentHolder {
+ virtual ~CommentHolder() {}
+ virtual grpc::string GetLeadingComments() const = 0;
+ virtual grpc::string GetTrailingComments() const = 0;
+};
+
// An abstract interface representing a method.
-struct Method {
+struct Method : public CommentHolder {
virtual ~Method() {}
virtual grpc::string name() const = 0;
@@ -80,7 +88,7 @@ struct Method {
};
// An abstract interface representing a service.
-struct Service {
+struct Service : public CommentHolder {
virtual ~Service() {}
virtual grpc::string name() const = 0;
@@ -101,7 +109,7 @@ struct Printer {
// An interface that allows the source generated to be output using various
// libraries/idls/serializers.
-struct File {
+struct File : public CommentHolder {
virtual ~File() {}
virtual grpc::string filename() const = 0;
diff --git a/src/compiler/cpp_plugin.cc b/src/compiler/cpp_plugin.cc
index e321c64639f..0ec183e474e 100644
--- a/src/compiler/cpp_plugin.cc
+++ b/src/compiler/cpp_plugin.cc
@@ -35,11 +35,15 @@
//
#include
+#include
#include "src/compiler/config.h"
#include "src/compiler/cpp_generator.h"
#include "src/compiler/cpp_generator_helpers.h"
+#include "src/compiler/generator_helpers.h"
+
+using grpc_generator::GetCppComments;
class ProtoBufMethod : public grpc_cpp_generator::Method {
public:
@@ -71,6 +75,14 @@ class ProtoBufMethod : public grpc_cpp_generator::Method {
return method_->client_streaming() && method_->server_streaming();
}
+ grpc::string GetLeadingComments() const {
+ return GetCppComments(method_, true);
+ }
+
+ grpc::string GetTrailingComments() const {
+ return GetCppComments(method_, false);
+ }
+
private:
const grpc::protobuf::MethodDescriptor *method_;
};
@@ -88,6 +100,14 @@ class ProtoBufService : public grpc_cpp_generator::Service {
new ProtoBufMethod(service_->method(i)));
};
+ grpc::string GetLeadingComments() const {
+ return GetCppComments(service_, true);
+ }
+
+ grpc::string GetTrailingComments() const {
+ return GetCppComments(service_, false);
+ }
+
private:
const grpc::protobuf::ServiceDescriptor *service_;
};
@@ -141,6 +161,14 @@ class ProtoBufFile : public grpc_cpp_generator::File {
new ProtoBufPrinter(str));
}
+ grpc::string GetLeadingComments() const {
+ return GetCppComments(file_, true);
+ }
+
+ grpc::string GetTrailingComments() const {
+ return GetCppComments(file_, false);
+ }
+
private:
const grpc::protobuf::FileDescriptor *file_;
};
diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc
index 4def6c5e31f..ac0fee1ec4d 100644
--- a/src/compiler/csharp_generator.cc
+++ b/src/compiler/csharp_generator.cc
@@ -52,6 +52,7 @@ using grpc::protobuf::MethodDescriptor;
using grpc::protobuf::io::Printer;
using grpc::protobuf::io::StringOutputStream;
using grpc_generator::MethodType;
+using grpc_generator::GetCppComments;
using grpc_generator::GetMethodType;
using grpc_generator::METHODTYPE_NO_STREAMING;
using grpc_generator::METHODTYPE_CLIENT_STREAMING;
@@ -65,6 +66,56 @@ using std::vector;
namespace grpc_csharp_generator {
namespace {
+// This function is a massaged version of
+// https://github.com/google/protobuf/blob/master/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
+// Currently, we cannot easily reuse the functionality as
+// google/protobuf/compiler/csharp/csharp_doc_comment.h is not a public header.
+// TODO(jtattermusch): reuse the functionality from google/protobuf.
+void GenerateDocCommentBodyImpl(grpc::protobuf::io::Printer* printer, grpc::protobuf::SourceLocation location) {
+ grpc::string comments = location.leading_comments.empty() ?
+ location.trailing_comments : location.leading_comments;
+ if (comments.empty()) {
+ return;
+ }
+ // XML escaping... no need for apostrophes etc as the whole text is going to be a child
+ // node of a summary element, not part of an attribute.
+ comments = grpc_generator::StringReplace(comments, "&", "&", true);
+ comments = grpc_generator::StringReplace(comments, "<", "<", true);
+
+ std::vector lines;
+ grpc_generator::Split(comments, '\n', &lines);
+ // TODO: We really should work out which part to put in the summary and which to put in the remarks...
+ // but that needs to be part of a bigger effort to understand the markdown better anyway.
+ printer->Print("/// \n");
+ bool last_was_empty = false;
+ // We squash multiple blank lines down to one, and remove any trailing blank lines. We need
+ // to preserve the blank lines themselves, as this is relevant in the markdown.
+ // Note that we can't remove leading or trailing whitespace as *that's* relevant in markdown too.
+ // (We don't skip "just whitespace" lines, either.)
+ for (std::vector::iterator it = lines.begin(); it != lines.end(); ++it) {
+ grpc::string line = *it;
+ if (line.empty()) {
+ last_was_empty = true;
+ } else {
+ if (last_was_empty) {
+ printer->Print("///\n");
+ }
+ last_was_empty = false;
+ printer->Print("/// $line$\n", "line", *it);
+ }
+ }
+ printer->Print("/// \n");
+}
+
+template
+void GenerateDocCommentBody(
+ grpc::protobuf::io::Printer* printer, const DescriptorType* descriptor) {
+ grpc::protobuf::SourceLocation location;
+ if (descriptor->GetSourceLocation(&location)) {
+ GenerateDocCommentBodyImpl(printer, location);
+ }
+}
+
std::string GetServiceClassName(const ServiceDescriptor* service) {
return service->name();
}
@@ -123,6 +174,10 @@ std::string GetMethodRequestParamMaybe(const MethodDescriptor *method,
return GetClassName(method->input_type()) + " request, ";
}
+std::string GetAccessLevel(bool internal_access) {
+ return internal_access ? "internal" : "public";
+}
+
std::string GetMethodReturnTypeClient(const MethodDescriptor *method) {
switch (GetMethodType(method)) {
case METHODTYPE_NO_STREAMING:
@@ -238,7 +293,7 @@ void GenerateStaticMethodField(Printer* out, const MethodDescriptor *method) {
void GenerateServiceDescriptorProperty(Printer* out, const ServiceDescriptor *service) {
std::ostringstream index;
index << service->index();
- out->Print("// service descriptor\n");
+ out->Print("/// Service descriptor\n");
out->Print("public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor\n");
out->Print("{\n");
out->Print(" get { return $umbrella$.Descriptor.Services[$index$]; }\n",
@@ -249,7 +304,8 @@ void GenerateServiceDescriptorProperty(Printer* out, const ServiceDescriptor *se
}
void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
- out->Print("// client interface\n");
+ out->Print("/// Client for $servicename$\n",
+ "servicename", GetServiceClassName(service));
out->Print("[System.Obsolete(\"Client side interfaced will be removed "
"in the next release. Use client class directly.\")]\n");
out->Print("public interface $name$\n", "name",
@@ -262,6 +318,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
if (method_type == METHODTYPE_NO_STREAMING) {
// unary calls have an extra synchronous stub method
+ GenerateDocCommentBody(out, method);
out->Print(
"$response$ $methodname$($request$ request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));\n",
"methodname", method->name(), "request",
@@ -269,6 +326,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
GetClassName(method->output_type()));
// overload taking CallOptions as a param
+ GenerateDocCommentBody(out, method);
out->Print(
"$response$ $methodname$($request$ request, CallOptions options);\n",
"methodname", method->name(), "request",
@@ -280,6 +338,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
if (method_type == METHODTYPE_NO_STREAMING) {
method_name += "Async"; // prevent name clash with synchronous method.
}
+ GenerateDocCommentBody(out, method);
out->Print(
"$returntype$ $methodname$($request_maybe$Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));\n",
"methodname", method_name, "request_maybe",
@@ -287,6 +346,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
GetMethodReturnTypeClient(method));
// overload taking CallOptions as a param
+ GenerateDocCommentBody(out, method);
out->Print(
"$returntype$ $methodname$($request_maybe$CallOptions options);\n",
"methodname", method_name, "request_maybe",
@@ -299,7 +359,8 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
}
void GenerateServerInterface(Printer* out, const ServiceDescriptor *service) {
- out->Print("// server-side interface\n");
+ out->Print("/// Interface of server-side implementations of $servicename$\n",
+ "servicename", GetServiceClassName(service));
out->Print("[System.Obsolete(\"Service implementations should inherit"
" from the generated abstract base class instead.\")]\n");
out->Print("public interface $name$\n", "name",
@@ -308,6 +369,7 @@ void GenerateServerInterface(Printer* out, const ServiceDescriptor *service) {
out->Indent();
for (int i = 0; i < service->method_count(); i++) {
const MethodDescriptor *method = service->method(i);
+ GenerateDocCommentBody(out, method);
out->Print(
"$returntype$ $methodname$($request$$response_stream_maybe$, "
"ServerCallContext context);\n",
@@ -322,13 +384,15 @@ void GenerateServerInterface(Printer* out, const ServiceDescriptor *service) {
}
void GenerateServerClass(Printer* out, const ServiceDescriptor *service) {
- out->Print("// server-side abstract class\n");
+ out->Print("/// Base class for server-side implementations of $servicename$\n",
+ "servicename", GetServiceClassName(service));
out->Print("public abstract class $name$\n", "name",
GetServerClassName(service));
out->Print("{\n");
out->Indent();
for (int i = 0; i < service->method_count(); i++) {
const MethodDescriptor *method = service->method(i);
+ GenerateDocCommentBody(out, method);
out->Print(
"public virtual $returntype$ $methodname$($request$$response_stream_maybe$, "
"ServerCallContext context)\n",
@@ -349,7 +413,8 @@ void GenerateServerClass(Printer* out, const ServiceDescriptor *service) {
}
void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
- out->Print("// client stub\n");
+ out->Print("/// Client for $servicename$\n",
+ "servicename", GetServiceClassName(service));
out->Print("#pragma warning disable 0618\n");
out->Print(
"public class $name$ : ClientBase<$name$>, $interface$\n",
@@ -388,6 +453,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
if (method_type == METHODTYPE_NO_STREAMING) {
// unary calls have an extra synchronous stub method
+ GenerateDocCommentBody(out, method);
out->Print("public virtual $response$ $methodname$($request$ request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))\n",
"methodname", method->name(), "request",
GetClassName(method->input_type()), "response",
@@ -400,6 +466,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
out->Print("}\n");
// overload taking CallOptions as a param
+ GenerateDocCommentBody(out, method);
out->Print("public virtual $response$ $methodname$($request$ request, CallOptions options)\n",
"methodname", method->name(), "request",
GetClassName(method->input_type()), "response",
@@ -416,6 +483,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
if (method_type == METHODTYPE_NO_STREAMING) {
method_name += "Async"; // prevent name clash with synchronous method.
}
+ GenerateDocCommentBody(out, method);
out->Print(
"public virtual $returntype$ $methodname$($request_maybe$Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))\n",
"methodname", method_name, "request_maybe",
@@ -431,6 +499,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
out->Print("}\n");
// overload taking CallOptions as a param
+ GenerateDocCommentBody(out, method);
out->Print(
"public virtual $returntype$ $methodname$($request_maybe$CallOptions options)\n",
"methodname", method_name, "request_maybe",
@@ -481,7 +550,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
void GenerateBindServiceMethod(Printer* out, const ServiceDescriptor *service,
bool use_server_class) {
out->Print(
- "// creates service definition that can be registered with a server\n");
+ "/// Creates service definition that can be registered with a server\n");
out->Print("#pragma warning disable 0618\n");
out->Print(
"public static ServerServiceDefinition BindService($interface$ serviceImpl)\n",
@@ -515,7 +584,8 @@ void GenerateBindServiceMethod(Printer* out, const ServiceDescriptor *service,
}
void GenerateNewStubMethods(Printer* out, const ServiceDescriptor *service) {
- out->Print("// creates a new client\n");
+ out->Print("/// Creates a new client for $servicename$\n",
+ "servicename", GetServiceClassName(service));
out->Print("public static $classname$ NewClient(Channel channel)\n",
"classname", GetClientClassName(service));
out->Print("{\n");
@@ -527,8 +597,12 @@ void GenerateNewStubMethods(Printer* out, const ServiceDescriptor *service) {
out->Print("\n");
}
-void GenerateService(Printer* out, const ServiceDescriptor *service) {
- out->Print("public static class $classname$\n", "classname",
+void GenerateService(Printer* out, const ServiceDescriptor *service,
+ bool generate_client, bool generate_server,
+ bool internal_access) {
+ GenerateDocCommentBody(out, service);
+ out->Print("$access_level$ static class $classname$\n", "access_level",
+ GetAccessLevel(internal_access), "classname",
GetServiceClassName(service));
out->Print("{\n");
out->Indent();
@@ -542,13 +616,22 @@ void GenerateService(Printer* out, const ServiceDescriptor *service) {
GenerateStaticMethodField(out, service->method(i));
}
GenerateServiceDescriptorProperty(out, service);
- GenerateClientInterface(out, service);
- GenerateServerInterface(out, service);
- GenerateServerClass(out, service);
- GenerateClientStub(out, service);
- GenerateBindServiceMethod(out, service, false);
- GenerateBindServiceMethod(out, service, true);
- GenerateNewStubMethods(out, service);
+
+ if (generate_client) {
+ GenerateClientInterface(out, service);
+ }
+ if (generate_server) {
+ GenerateServerInterface(out, service);
+ GenerateServerClass(out, service);
+ }
+ if (generate_client) {
+ GenerateClientStub(out, service);
+ GenerateNewStubMethods(out, service);
+ }
+ if (generate_server) {
+ GenerateBindServiceMethod(out, service, false);
+ GenerateBindServiceMethod(out, service, true);
+ }
out->Outdent();
out->Print("}\n");
@@ -556,7 +639,8 @@ void GenerateService(Printer* out, const ServiceDescriptor *service) {
} // anonymous namespace
-grpc::string GetServices(const FileDescriptor *file) {
+grpc::string GetServices(const FileDescriptor *file, bool generate_client,
+ bool generate_server, bool internal_access) {
grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
@@ -573,6 +657,14 @@ grpc::string GetServices(const FileDescriptor *file) {
// Write out a file header.
out.Print("// Generated by the protocol buffer compiler. DO NOT EDIT!\n");
out.Print("// source: $filename$\n", "filename", file->name());
+
+ // use C++ style as there are no file-level XML comments in .NET
+ grpc::string leading_comments = GetCppComments(file, true);
+ if (!leading_comments.empty()) {
+ out.Print("// Original file comments:\n");
+ out.Print(leading_comments.c_str());
+ }
+
out.Print("#region Designer generated code\n");
out.Print("\n");
out.Print("using System;\n");
@@ -584,7 +676,8 @@ grpc::string GetServices(const FileDescriptor *file) {
out.Print("namespace $namespace$ {\n", "namespace", GetFileNamespace(file));
out.Indent();
for (int i = 0; i < file->service_count(); i++) {
- GenerateService(&out, file->service(i));
+ GenerateService(&out, file->service(i), generate_client, generate_server,
+ internal_access);
}
out.Outdent();
out.Print("}\n");
diff --git a/src/compiler/csharp_generator.h b/src/compiler/csharp_generator.h
index 90eb7e29846..f0585af4fd7 100644
--- a/src/compiler/csharp_generator.h
+++ b/src/compiler/csharp_generator.h
@@ -40,7 +40,9 @@
namespace grpc_csharp_generator {
-grpc::string GetServices(const grpc::protobuf::FileDescriptor *file);
+grpc::string GetServices(const grpc::protobuf::FileDescriptor *file,
+ bool generate_client, bool generate_server,
+ bool internal_access);
} // namespace grpc_csharp_generator
diff --git a/src/compiler/csharp_plugin.cc b/src/compiler/csharp_plugin.cc
index 8b9395f9e2b..5350e73f108 100644
--- a/src/compiler/csharp_plugin.cc
+++ b/src/compiler/csharp_plugin.cc
@@ -48,7 +48,29 @@ class CSharpGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
const grpc::string ¶meter,
grpc::protobuf::compiler::GeneratorContext *context,
grpc::string *error) const {
- grpc::string code = grpc_csharp_generator::GetServices(file);
+ std::vector > options;
+ grpc::protobuf::compiler::ParseGeneratorParameter(parameter, &options);
+
+ bool generate_client = true;
+ bool generate_server = true;
+ bool internal_access = false;
+ for (size_t i = 0; i < options.size(); i++) {
+ if (options[i].first == "no_client") {
+ generate_client = false;
+ } else if (options[i].first == "no_server") {
+ generate_server = false;
+ } else if (options[i].first == "internal_access") {
+ internal_access = true;
+ } else {
+ *error = "Unknown generator option: " + options[i].first;
+ return false;
+ }
+ }
+
+ grpc::string code = grpc_csharp_generator::GetServices(file,
+ generate_client,
+ generate_server,
+ internal_access);
if (code.size() == 0) {
return true; // don't generate a file if there are no services
}
diff --git a/src/compiler/generator_helpers.h b/src/compiler/generator_helpers.h
index 3ed0500efc5..bd077cf7983 100644
--- a/src/compiler/generator_helpers.h
+++ b/src/compiler/generator_helpers.h
@@ -34,7 +34,11 @@
#ifndef GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H
#define GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H
+#include
#include