Add protoc plugin.

Original patch by igorgatis@gmail.com, tweaked a little before commit.

Fixes issue 90.
pull/288/head
Jon Skeet 11 years ago
parent fd6c129298
commit 92d6214e0f
  1. 3
      build/build.csproj
  2. 147
      protos/google/protobuf/compiler/plugin.proto
  3. 12
      src/ProtoGen.Test/DependencyResolutionTest.cs
  4. 683
      src/ProtoGen.Test/ProtocGenCsUnittests.cs
  5. 101
      src/ProtoGen.Test/protoc-gen-cs.Test.csproj
  6. 44
      src/ProtoGen/Generator.cs
  7. 1187
      src/ProtoGen/PluginProtoFile.cs
  8. 29
      src/ProtoGen/Program.cs
  9. 1
      src/ProtoGen/ProtoGen.csproj
  10. 76
      src/ProtoGen/ProtocGenCs.cs
  11. 101
      src/ProtoGen/protoc-gen-cs.csproj
  12. 22
      src/ProtocolBuffers.sln

@ -189,6 +189,9 @@
<StaticPackageItem Include="$(ProjectDirectory)\protos\google\protobuf\descriptor.proto">
<TargetDirectory>\protos\google\protobuf</TargetDirectory>
</StaticPackageItem>
<StaticPackageItem Include="$(ProjectDirectory)\protos\google\protobuf\compiler\plugin.proto">
<TargetDirectory>\protos\google\protobuf\compiler</TargetDirectory>
</StaticPackageItem>
<StaticPackageItem Include="$(ProjectDirectory)\protos\google\protobuf\csharp_options.proto">
<TargetDirectory>\protos\google\protobuf</TargetDirectory>
</StaticPackageItem>

@ -0,0 +1,147 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
//
// WARNING: The plugin interface is currently EXPERIMENTAL and is subject to
// change.
//
// protoc (aka the Protocol Compiler) can be extended via plugins. A plugin is
// just a program that reads a CodeGeneratorRequest from stdin and writes a
// CodeGeneratorResponse to stdout.
//
// Plugins written using C++ can use google/protobuf/compiler/plugin.h instead
// of dealing with the raw protocol defined here.
//
// A plugin executable needs only to be placed somewhere in the path. The
// plugin should be named "protoc-gen-$NAME", and will then be used when the
// flag "--${NAME}_out" is passed to protoc.
package google.protobuf.compiler;
option java_package = "com.google.protobuf.compiler";
option java_outer_classname = "PluginProtos";
import "google/protobuf/descriptor.proto";
// An encoded CodeGeneratorRequest is written to the plugin's stdin.
message CodeGeneratorRequest {
// The .proto files that were explicitly listed on the command-line. The
// code generator should generate code only for these files. Each file's
// descriptor will be included in proto_file, below.
repeated string file_to_generate = 1;
// The generator parameter passed on the command-line.
optional string parameter = 2;
// FileDescriptorProtos for all files in files_to_generate and everything
// they import. The files will appear in topological order, so each file
// appears before any file that imports it.
//
// protoc guarantees that all proto_files will be written after
// the fields above, even though this is not technically guaranteed by the
// protobuf wire format. This theoretically could allow a plugin to stream
// in the FileDescriptorProtos and handle them one by one rather than read
// the entire set into memory at once. However, as of this writing, this
// is not similarly optimized on protoc's end -- it will store all fields in
// memory at once before sending them to the plugin.
repeated FileDescriptorProto proto_file = 15;
}
// The plugin writes an encoded CodeGeneratorResponse to stdout.
message CodeGeneratorResponse {
// Error message. If non-empty, code generation failed. The plugin process
// should exit with status code zero even if it reports an error in this way.
//
// This should be used to indicate errors in .proto files which prevent the
// code generator from generating correct code. Errors which indicate a
// problem in protoc itself -- such as the input CodeGeneratorRequest being
// unparseable -- should be reported by writing a message to stderr and
// exiting with a non-zero status code.
optional string error = 1;
// Represents a single generated file.
message File {
// The file name, relative to the output directory. The name must not
// contain "." or ".." components and must be relative, not be absolute (so,
// the file cannot lie outside the output directory). "/" must be used as
// the path separator, not "\".
//
// If the name is omitted, the content will be appended to the previous
// file. This allows the generator to break large files into small chunks,
// and allows the generated text to be streamed back to protoc so that large
// files need not reside completely in memory at one time. Note that as of
// this writing protoc does not optimize for this -- it will read the entire
// CodeGeneratorResponse before writing files to disk.
optional string name = 1;
// If non-empty, indicates that the named file should already exist, and the
// content here is to be inserted into that file at a defined insertion
// point. This feature allows a code generator to extend the output
// produced by another code generator. The original generator may provide
// insertion points by placing special annotations in the file that look
// like:
// @@protoc_insertion_point(NAME)
// The annotation can have arbitrary text before and after it on the line,
// which allows it to be placed in a comment. NAME should be replaced with
// an identifier naming the point -- this is what other generators will use
// as the insertion_point. Code inserted at this point will be placed
// immediately above the line containing the insertion point (thus multiple
// insertions to the same point will come out in the order they were added).
// The double-@ is intended to make it unlikely that the generated code
// could contain things that look like insertion points by accident.
//
// For example, the C++ code generator places the following line in the
// .pb.h files that it generates:
// // @@protoc_insertion_point(namespace_scope)
// This line appears within the scope of the file's package namespace, but
// outside of any particular class. Another plugin can then specify the
// insertion_point "namespace_scope" to generate additional classes or
// other declarations that should be placed in this scope.
//
// Note that if the line containing the insertion point begins with
// whitespace, the same whitespace will be added to every line of the
// inserted text. This is useful for languages like Python, where
// indentation matters. In these languages, the insertion point comment
// should be indented the same amount as any inserted code will need to be
// in order to work correctly in that context.
//
// The code generator that generates the initial file and the one which
// inserts into it must both run as part of a single invocation of protoc.
// Code generators are executed in the order in which they appear on the
// command line.
//
// If |insertion_point| is present, |name| must also be present.
optional string insertion_point = 2;
// The file contents.
optional string content = 15;
}
repeated File file = 15;
}

@ -52,7 +52,7 @@ namespace Google.ProtocolBuffers.ProtoGen
{
FileDescriptorProto first = new FileDescriptorProto.Builder {Name = "First"}.Build();
FileDescriptorProto second = new FileDescriptorProto.Builder {Name = "Second"}.Build();
FileDescriptorSet set = new FileDescriptorSet.Builder { FileList = { first, second } }.Build();
var set = new List<FileDescriptorProto> { first, second };
IList<FileDescriptor> converted = Generator.ConvertDescriptors(CSharpFileOptions.DefaultInstance, set);
Assert.AreEqual(2, converted.Count);
@ -68,7 +68,7 @@ namespace Google.ProtocolBuffers.ProtoGen
FileDescriptorProto first =
new FileDescriptorProto.Builder {Name = "First", DependencyList = {"Second"}}.Build();
FileDescriptorProto second = new FileDescriptorProto.Builder {Name = "Second"}.Build();
FileDescriptorSet set = new FileDescriptorSet.Builder { FileList = { first, second } }.Build();
var set = new List<FileDescriptorProto> { first, second };
IList<FileDescriptor> converted = Generator.ConvertDescriptors(CSharpFileOptions.DefaultInstance, set);
Assert.AreEqual(2, converted.Count);
Assert.AreEqual("First", converted[0].Name);
@ -84,7 +84,7 @@ namespace Google.ProtocolBuffers.ProtoGen
FileDescriptorProto first = new FileDescriptorProto.Builder {Name = "First"}.Build();
FileDescriptorProto second =
new FileDescriptorProto.Builder {Name = "Second", DependencyList = {"First"}}.Build();
FileDescriptorSet set = new FileDescriptorSet.Builder { FileList = { first, second } }.Build();
var set = new List<FileDescriptorProto> { first, second };
IList<FileDescriptor> converted = Generator.ConvertDescriptors(CSharpFileOptions.DefaultInstance, set);
Assert.AreEqual(2, converted.Count);
Assert.AreEqual("First", converted[0].Name);
@ -101,7 +101,7 @@ namespace Google.ProtocolBuffers.ProtoGen
new FileDescriptorProto.Builder {Name = "First", DependencyList = {"Second"}}.Build();
FileDescriptorProto second =
new FileDescriptorProto.Builder {Name = "Second", DependencyList = {"First"}}.Build();
FileDescriptorSet set = new FileDescriptorSet.Builder { FileList = { first, second } }.Build();
var set = new List<FileDescriptorProto> { first, second };
try
{
Generator.ConvertDescriptors(CSharpFileOptions.DefaultInstance, set);
@ -118,7 +118,7 @@ namespace Google.ProtocolBuffers.ProtoGen
{
FileDescriptorProto first =
new FileDescriptorProto.Builder {Name = "First", DependencyList = {"Second"}}.Build();
FileDescriptorSet set = new FileDescriptorSet.Builder { FileList = { first } }.Build();
var set = new List<FileDescriptorProto> { first };
try
{
Generator.ConvertDescriptors(CSharpFileOptions.DefaultInstance, set);
@ -135,7 +135,7 @@ namespace Google.ProtocolBuffers.ProtoGen
{
FileDescriptorProto first =
new FileDescriptorProto.Builder {Name = "First", DependencyList = {"First"}}.Build();
FileDescriptorSet set = new FileDescriptorSet.Builder { FileList = { first } }.Build();
var set = new List<FileDescriptorProto> { first };
try
{
Generator.ConvertDescriptors(CSharpFileOptions.DefaultInstance, set);

@ -0,0 +1,683 @@
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://github.com/jskeet/dotnet-protobufs/
// Original C++/Java/Python code:
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
namespace Google.ProtocolBuffers.ProtoGen
{
/// <summary>
/// Tests protoc-gen-cs plugin.
/// </summary>
[TestFixture]
[Category("Preprocessor")]
public partial class ProtocGenCsUnittests
{
private static readonly string TempPath = Path.Combine(Path.GetTempPath(), "protoc-gen-cs.Test");
private const string DefaultProto =
@"
package nunit.simple;
// Test a very simple message.
message MyMessage {
optional string name = 1;
}";
#region TestFixture SetUp/TearDown
private static readonly string OriginalWorkingDirectory = Environment.CurrentDirectory;
private StringBuilder buffer = new StringBuilder();
[TestFixtureSetUp]
public virtual void Setup()
{
Teardown();
Directory.CreateDirectory(TempPath);
Environment.CurrentDirectory = TempPath;
this.buffer.Length = 0;
}
[TestFixtureTearDown]
public virtual void Teardown()
{
Environment.CurrentDirectory = OriginalWorkingDirectory;
if (Directory.Exists(TempPath))
{
Directory.Delete(TempPath, true);
}
}
#endregion
#region Helper Methods RunProtoGen / RunCsc
private void RunProtoc(int expect, string protoFile, params string[] args)
{
string protoPath = string.Format("-I. -I\"{0}\"", OriginalWorkingDirectory);
string plugin = string.Format("--plugin=\"{0}\"", Path.Combine(OriginalWorkingDirectory, "protoc-gen-cs.exe"));
string csOut = args.Length == 0 ? "--cs_out=." : string.Format("--cs_out=\"{0}:.\"", string.Join(" ", args));
// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.WorkingDirectory = TempPath;
p.StartInfo.FileName = Path.Combine(OriginalWorkingDirectory, "protoc.exe");
p.StartInfo.Arguments = string.Join(" ", new string[] { plugin, csOut, protoPath, protoFile });
p.Start();
// Read the output stream first and then wait.
buffer.AppendLine(string.Format("{0}> \"{1}\" {2}", p.StartInfo.WorkingDirectory, p.StartInfo.FileName, p.StartInfo.Arguments));
buffer.AppendLine(p.StandardError.ReadToEnd());
buffer.AppendLine(p.StandardOutput.ReadToEnd());
p.WaitForExit();
Assert.AreEqual(expect, p.ExitCode, this.buffer.ToString());
}
private Assembly RunCsc(int expect, params string[] sources)
{
using (TempFile tempDll = new TempFile(String.Empty))
{
tempDll.ChangeExtension(".dll");
List<string> args = new List<string>();
args.Add("/nologo");
args.Add("/target:library");
args.Add("/debug-");
args.Add(String.Format(@"""/out:{0}""", tempDll.TempPath));
args.Add("/r:System.dll");
args.Add(String.Format(@"""/r:{0}""",
typeof(Google.ProtocolBuffers.DescriptorProtos.DescriptorProto).Assembly.
Location));
args.AddRange(sources);
string exe = Path.Combine(System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(),
"csc.exe");
ProcessStartInfo psi = new ProcessStartInfo(exe);
psi.WorkingDirectory = TempPath;
psi.CreateNoWindow = true;
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.Arguments = string.Join(" ", args.ToArray());
Process p = Process.Start(psi);
buffer.AppendLine(string.Format("{0}> \"{1}\" {2}", p.StartInfo.WorkingDirectory, p.StartInfo.FileName, p.StartInfo.Arguments));
buffer.AppendLine(p.StandardError.ReadToEnd());
buffer.AppendLine(p.StandardOutput.ReadToEnd());
p.WaitForExit();
Assert.AreEqual(expect, p.ExitCode, this.buffer.ToString());
Assembly asm = null;
if (p.ExitCode == 0)
{
byte[] allbytes = File.ReadAllBytes(tempDll.TempPath);
asm = Assembly.Load(allbytes);
foreach (Type t in asm.GetTypes())
{
Debug.WriteLine(t.FullName, asm.FullName);
}
}
return asm;
}
}
#endregion
// *******************************************************************
// The following tests excercise options for protogen.exe
// *******************************************************************
[Test]
public void TestProtoFile()
{
string test = new StackFrame(false).GetMethod().Name;
Setup();
using (TempFile source = TempFile.Attach(test + ".cs"))
using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
{
RunProtoc(0, proto.TempPath);
Assembly a = RunCsc(0, source.TempPath);
//assert that the message type is in the expected namespace
Type t = a.GetType("nunit.simple.MyMessage", true, true);
Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
//assert that we can find the static descriptor type
a.GetType("nunit.simple." + test, true, true);
}
}
[Test]
public void TestProtoFileWithConflictingType()
{
string test = new StackFrame(false).GetMethod().Name;
Setup();
using (TempFile source = TempFile.Attach(test + ".cs"))
using (
ProtoFile proto = new ProtoFile(test + ".proto",
@"
package nunit.simple;
// Test a very simple message.
message " +
test + @" {
optional string name = 1;
} "))
{
RunProtoc(0, proto.TempPath);
Assembly a = RunCsc(0, source.TempPath);
//assert that the message type is in the expected namespace
Type t = a.GetType("nunit.simple." + test, true, true);
Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
//assert that we can find the static descriptor type
a.GetType("nunit.simple.Proto." + test, true, true);
}
}
[Test]
public void TestProtoFileWithNamespace()
{
string test = new StackFrame(false).GetMethod().Name;
Setup();
using (TempFile source = TempFile.Attach(test + ".cs"))
using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
{
RunProtoc(0, proto.TempPath, "-namespace=MyNewNamespace");
Assembly a = RunCsc(0, source.TempPath);
//assert that the message type is in the expected namespace
Type t = a.GetType("MyNewNamespace.MyMessage", true, true);
Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
//assert that we can find the static descriptor type
a.GetType("MyNewNamespace." + test, true, true);
}
}
[Test]
public void TestProtoFileWithUmbrellaClassName()
{
string test = new StackFrame(false).GetMethod().Name;
Setup();
using (TempFile source = TempFile.Attach("MyUmbrellaClassname.cs"))
using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
{
RunProtoc(0, proto.TempPath, "/umbrella_classname=MyUmbrellaClassname");
Assembly a = RunCsc(0, source.TempPath);
//assert that the message type is in the expected namespace
Type t = a.GetType("nunit.simple.MyMessage", true, true);
Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
//assert that we can find the static descriptor type
a.GetType("nunit.simple.MyUmbrellaClassname", true, true);
}
}
[Test]
public void TestProtoFileWithNestedClass()
{
string test = new StackFrame(false).GetMethod().Name;
Setup();
using (TempFile source = TempFile.Attach(test + ".cs"))
using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
{
RunProtoc(0, proto.TempPath, "-nest_classes=true");
Assembly a = RunCsc(0, source.TempPath);
//assert that the message type is in the expected namespace
Type t = a.GetType("nunit.simple." + test + "+MyMessage", true, true);
Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
//assert that we can find the static descriptor type
a.GetType("nunit.simple." + test, true, true);
}
}
[Test]
public void TestProtoFileWithExpandedNsDirectories()
{
string test = new StackFrame(false).GetMethod().Name;
Setup();
using (TempFile source = TempFile.Attach(@"nunit\simple\" + test + ".cs"))
using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
{
RunProtoc(0, proto.TempPath, "-expand_namespace_directories=true");
Assembly a = RunCsc(0, source.TempPath);
//assert that the message type is in the expected namespace
Type t = a.GetType("nunit.simple.MyMessage", true, true);
Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
//assert that we can find the static descriptor type
a.GetType("nunit.simple." + test, true, true);
}
}
[Test]
public void TestProtoFileWithNewExtension()
{
string test = new StackFrame(false).GetMethod().Name;
Setup();
using (TempFile source = TempFile.Attach(test + ".Generated.cs"))
using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
{
RunProtoc(0, proto.TempPath, "-file_extension=.Generated.cs");
Assembly a = RunCsc(0, source.TempPath);
//assert that the message type is in the expected namespace
Type t = a.GetType("nunit.simple.MyMessage", true, true);
Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
//assert that we can find the static descriptor type
a.GetType("nunit.simple." + test, true, true);
}
}
[Test]
public void TestProtoFileWithUmbrellaNamespace()
{
string test = new StackFrame(false).GetMethod().Name;
Setup();
using (TempFile source = TempFile.Attach(test + ".cs"))
using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
{
RunProtoc(0, proto.TempPath, "-umbrella_namespace=MyUmbrella.Namespace");
Assembly a = RunCsc(0, source.TempPath);
//assert that the message type is in the expected namespace
Type t = a.GetType("nunit.simple.MyMessage", true, true);
Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
//assert that we can find the static descriptor type
a.GetType("nunit.simple.MyUmbrella.Namespace." + test, true, true);
}
}
[Test]
public void TestProtoFileWithIgnoredUmbrellaNamespaceDueToNesting()
{
string test = new StackFrame(false).GetMethod().Name;
Setup();
using (TempFile source = TempFile.Attach(test + ".cs"))
using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
{
RunProtoc(0, proto.TempPath, "-nest_classes=true", "-umbrella_namespace=MyUmbrella.Namespace");
Assembly a = RunCsc(0, source.TempPath);
//assert that the message type is in the expected namespace
Type t = a.GetType("nunit.simple." + test + "+MyMessage", true, true);
Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
//assert that we can find the static descriptor type
a.GetType("nunit.simple." + test, true, true);
}
}
[Test]
public void TestProtoFileWithExplicitEmptyUmbrellaNamespace()
{
string test = new StackFrame(false).GetMethod().Name;
Setup();
using (TempFile source = TempFile.Attach(test + ".cs"))
using (
ProtoFile proto = new ProtoFile(test + ".proto",
@"
package nunit.simple;
// Test a very simple message.
message " +
test + @" {
optional string name = 1;
} "))
{
//Forces the umbrella class to not use a namespace even if a collision with a type is detected.
RunProtoc(0, proto.TempPath, "-umbrella_namespace=");
//error CS0441: 'nunit.simple.TestProtoFileWithExplicitEmptyUmbrellaNamespace': a class cannot be both static and sealed
RunCsc(1, source.TempPath);
}
}
[Test]
public void TestProtoFileWithNewOutputFolder()
{
string test = new StackFrame(false).GetMethod().Name;
Setup();
using (TempFile source = TempFile.Attach(@"generated-code\" + test + ".cs"))
using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
{
RunProtoc(1, proto.TempPath, "-output_directory=generated-code");
Directory.CreateDirectory("generated-code");
RunProtoc(0, proto.TempPath, "-output_directory=generated-code");
Assembly a = RunCsc(0, source.TempPath);
//assert that the message type is in the expected namespace
Type t = a.GetType("nunit.simple.MyMessage", true, true);
Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
//assert that we can find the static descriptor type
a.GetType("nunit.simple." + test, true, true);
}
}
[Test]
public void TestProtoFileAndIgnoreGoogleProtobuf()
{
string test = new StackFrame(false).GetMethod().Name;
Setup();
using (TempFile source = TempFile.Attach(test + ".cs"))
using (
ProtoFile proto = new ProtoFile(test + ".proto",
@"
import ""google/protobuf/csharp_options.proto"";
option (google.protobuf.csharp_file_options).namespace = ""MyNewNamespace"";
" +
DefaultProto))
{
string google = Path.Combine(TempPath, "google\\protobuf");
Directory.CreateDirectory(google);
foreach (string file in Directory.GetFiles(Path.Combine(OriginalWorkingDirectory, "google\\protobuf")))
{
File.Copy(file, Path.Combine(google, Path.GetFileName(file)));
}
Assert.AreEqual(0, Directory.GetFiles(TempPath, "*.cs").Length);
RunProtoc(0, proto.TempPath);
Assert.AreEqual(1, Directory.GetFiles(TempPath, "*.cs").Length);
Assembly a = RunCsc(0, source.TempPath);
//assert that the message type is in the expected namespace
Type t = a.GetType("MyNewNamespace.MyMessage", true, true);
Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
//assert that we can find the static descriptor type
a.GetType("MyNewNamespace." + test, true, true);
}
}
[Test]
public void TestProtoFileWithoutIgnoreGoogleProtobuf()
{
string test = new StackFrame(false).GetMethod().Name;
Setup();
using (TempFile source = TempFile.Attach(test + ".cs"))
using (
ProtoFile proto = new ProtoFile(test + ".proto",
@"
import ""google/protobuf/csharp_options.proto"";
option (google.protobuf.csharp_file_options).namespace = ""MyNewNamespace"";
" +
DefaultProto))
{
string google = Path.Combine(TempPath, "google\\protobuf");
Directory.CreateDirectory(google);
foreach (string file in Directory.GetFiles(Path.Combine(OriginalWorkingDirectory, "google\\protobuf")))
{
File.Copy(file, Path.Combine(google, Path.GetFileName(file)));
}
Assert.AreEqual(0, Directory.GetFiles(TempPath, "*.cs").Length);
//Without the option this fails due to being unable to resolve google/protobuf descriptors
RunProtoc(0, proto.TempPath);
}
}
// *******************************************************************
// The following tests excercise options for protoc.exe
// *******************************************************************
[Test]
public void TestProtoFileWithIncludeImports()
{
string test = new StackFrame(false).GetMethod().Name;
Setup();
using (TempFile source = TempFile.Attach(test + ".cs"))
using (
ProtoFile proto = new ProtoFile(test + ".proto",
@"
import ""google/protobuf/csharp_options.proto"";
option (google.protobuf.csharp_file_options).namespace = ""MyNewNamespace"";
package nunit.simple;
// Test a very simple message.
message MyMessage {
optional string name = 1;
} ")
)
{
string google = Path.Combine(TempPath, "google\\protobuf");
Directory.CreateDirectory(google);
foreach (string file in Directory.GetFiles(Path.Combine(OriginalWorkingDirectory, "google\\protobuf")))
{
File.Copy(file, Path.Combine(google, Path.GetFileName(file)));
}
Assert.AreEqual(0, Directory.GetFiles(TempPath, "*.cs").Length);
//if you specify the protoc option --include_imports this should build three source files
RunProtoc(0, proto.TempPath);
Assert.AreEqual(1, Directory.GetFiles(TempPath, "*.cs").Length);
//you can (and should) simply omit the inclusion of the extra source files in your project
Assembly a = RunCsc(0, source.TempPath);
//assert that the message type is in the expected namespace
Type t = a.GetType("MyNewNamespace.MyMessage", true, true);
Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
//assert that we can find the static descriptor type
a.GetType("MyNewNamespace." + test, true, true);
}
}
//Seems the --proto_path or -I option is non-functional for me. Maybe others have luck?
[Test]
public void TestProtoFileInDifferentDirectory()
{
string test = new StackFrame(false).GetMethod().Name;
Setup();
using (TempFile source = TempFile.Attach(test + ".cs"))
using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
{
Environment.CurrentDirectory = OriginalWorkingDirectory;
RunProtoc(0, proto.TempPath);
Assembly a = RunCsc(0, source.TempPath);
//assert that the message type is in the expected namespace
Type t = a.GetType("nunit.simple.MyMessage", true, true);
Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
//assert that we can find the static descriptor type
a.GetType("nunit.simple." + test, true, true);
}
}
// *******************************************************************
// Handling of mutliple input files
// *******************************************************************
[Test]
public void TestMultipleProtoFiles()
{
Setup();
using (TempFile source1 = TempFile.Attach("MyMessage.cs"))
using (
ProtoFile proto1 = new ProtoFile("MyMessage.proto",
@"
package nunit.simple;
// Test a very simple message.
message MyMessage {
optional string name = 1;
}")
)
using (TempFile source2 = TempFile.Attach("MyMessageList.cs"))
using (
ProtoFile proto2 = new ProtoFile("MyMessageList.proto",
@"
package nunit.simple;
import ""MyMessage.proto"";
// Test a very simple message.
message MyMessageList {
repeated MyMessage messages = 1;
}")
)
{
RunProtoc(0, proto1.TempPath);
RunProtoc(0, proto2.TempPath);
Assembly a = RunCsc(0, source1.TempPath, source2.TempPath);
//assert that the message type is in the expected namespace
Type t1 = a.GetType("nunit.simple.MyMessage", true, true);
Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t1), "Expect an IMessage");
//assert that the message type is in the expected namespace
Type t2 = a.GetType("nunit.simple.MyMessageList", true, true);
Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t2), "Expect an IMessage");
//assert that we can find the static descriptor type
a.GetType("nunit.simple.Proto.MyMessage", true, true);
a.GetType("nunit.simple.Proto.MyMessageList", true, true);
}
}
[Test]
public void TestOneProtoFileWithBufferFile()
{
Setup();
using (TempFile source1 = TempFile.Attach("MyMessage.cs"))
using (
ProtoFile proto1 = new ProtoFile("MyMessage.proto",
@"
package nunit.simple;
// Test a very simple message.
message MyMessage {
optional string name = 1;
}")
)
using (TempFile source2 = TempFile.Attach("MyMessageList.cs"))
using (
ProtoFile proto2 = new ProtoFile("MyMessageList.proto",
@"
package nunit.simple;
import ""MyMessage.proto"";
// Test a very simple message.
message MyMessageList {
repeated MyMessage messages = 1;
}")
)
{
//build the proto buffer for MyMessage
RunProtoc(0, proto1.TempPath);
//build the MyMessageList proto-buffer and generate code by including MyMessage.pb
RunProtoc(0, proto2.TempPath);
Assembly a = RunCsc(0, source1.TempPath, source2.TempPath);
//assert that the message type is in the expected namespace
Type t1 = a.GetType("nunit.simple.MyMessage", true, true);
Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t1), "Expect an IMessage");
//assert that the message type is in the expected namespace
Type t2 = a.GetType("nunit.simple.MyMessageList", true, true);
Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t2), "Expect an IMessage");
//assert that we can find the static descriptor type
a.GetType("nunit.simple.Proto.MyMessage", true, true);
a.GetType("nunit.simple.Proto.MyMessageList", true, true);
}
}
[Test]
public void TestProtoFileWithService()
{
string test = new StackFrame(false).GetMethod().Name;
Setup();
using (TempFile source = TempFile.Attach(test + ".cs"))
using (ProtoFile proto = new ProtoFile(test + ".proto",
@"
import ""google/protobuf/csharp_options.proto"";
option (google.protobuf.csharp_file_options).service_generator_type = GENERIC;
package nunit.simple;
// Test a very simple message.
message MyMessage {
optional string name = 1;
}
// test a very simple service.
service TestService {
rpc Execute (MyMessage) returns (MyMessage);
}"))
{
CopyInGoogleProtoFiles();
RunProtoc(0, proto.TempPath, "-nest_classes=false");
Assert.AreEqual(1, Directory.GetFiles(TempPath, "*.cs").Length);
Assembly a = RunCsc(0, source.TempPath);
//assert that the service type is in the expected namespace
Type t1 = a.GetType("nunit.simple.TestService", true, true);
Assert.IsTrue(typeof(IService).IsAssignableFrom(t1), "Expect an IService");
Assert.IsTrue(t1.IsAbstract, "Expect abstract class");
//assert that the Stub subclass type is in the expected namespace
Type t2 = a.GetType("nunit.simple.TestService+Stub", true, true);
Assert.IsTrue(t1.IsAssignableFrom(t2), "Expect a sub of TestService");
Assert.IsFalse(t2.IsAbstract, "Expect concrete class");
}
}
[Test]
public void TestProtoFileWithServiceInternal()
{
string test = new StackFrame(false).GetMethod().Name;
Setup();
using (TempFile source = TempFile.Attach(test + ".cs"))
using (ProtoFile proto = new ProtoFile(test + ".proto",
@"
import ""google/protobuf/csharp_options.proto"";
option (google.protobuf.csharp_file_options).service_generator_type = GENERIC;
package nunit.simple;
// Test a very simple message.
message MyMessage {
optional string name = 1;
}
// test a very simple service.
service TestService {
rpc Execute (MyMessage) returns (MyMessage);
}"))
{
CopyInGoogleProtoFiles();
RunProtoc(0, proto.TempPath, "-nest_classes=false", "-public_classes=false");
Assert.AreEqual(1, Directory.GetFiles(TempPath, "*.cs").Length);
Assembly a = RunCsc(0, source.TempPath);
//assert that the service type is in the expected namespace
Type t1 = a.GetType("nunit.simple.TestService", true, true);
Assert.IsTrue(typeof(IService).IsAssignableFrom(t1), "Expect an IService");
Assert.IsTrue(t1.IsAbstract, "Expect abstract class");
//assert that the Stub subclass type is in the expected namespace
Type t2 = a.GetType("nunit.simple.TestService+Stub", true, true);
Assert.IsTrue(t1.IsAssignableFrom(t2), "Expect a sub of TestService");
Assert.IsFalse(t2.IsAbstract, "Expect concrete class");
}
}
private static void CopyInGoogleProtoFiles()
{
string google = Path.Combine(TempPath, "google\\protobuf");
Directory.CreateDirectory(google);
foreach (string file in Directory.GetFiles(Path.Combine(OriginalWorkingDirectory, "google\\protobuf")))
{
File.Copy(file, Path.Combine(google, Path.GetFileName(file)));
}
}
}
}

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<EnvironmentFlavor>CLIENTPROFILE</EnvironmentFlavor>
<EnvironmentTemplate>NET35</EnvironmentTemplate>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{C1024C9C-8176-48C3-B547-B9F6DF6B80A6}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Google.ProtocolBuffers.ProtoGen</RootNamespace>
<AssemblyName>protoc-gen-cs.Test</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\NET35\Debug</OutputPath>
<IntermediateOutputPath>obj\NET35\Debug\</IntermediateOutputPath>
<DefineConstants>DEBUG;TRACE;$(EnvironmentFlavor);$(EnvironmentTemplate)</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<NoStdLib>true</NoStdLib>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\NET35\Release</OutputPath>
<IntermediateOutputPath>obj\NET35\Release\</IntermediateOutputPath>
<DefineConstants>TRACE;$(EnvironmentFlavor);$(EnvironmentTemplate)</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<NoStdLib>true</NoStdLib>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
</PropertyGroup>
<ItemGroup>
<Reference Include="nunit.framework">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\NUnit\lib\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ProtocGenCsUnittests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TempFile.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ProtocolBuffers\ProtocolBuffers.csproj">
<Project>{6908bdce-d925-43f3-94ac-a531e6df2591}</Project>
<Name>ProtocolBuffers</Name>
</ProjectReference>
<ProjectReference Include="..\ProtoGen\protoc-gen-cs.csproj">
<Project>{250ade34-82fd-4bae-86d5-985fbe589c4b}</Project>
<Name>protoc-gen-cs</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="..\..\lib\protoc.exe">
<Link>protoc.exe</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<None Include="..\..\protos\google\protobuf\csharp_options.proto">
<Link>google\protobuf\csharp_options.proto</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="..\..\protos\google\protobuf\descriptor.proto">
<Link>google\protobuf\descriptor.proto</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<PropertyGroup>
<StartAction>Program</StartAction>
<StartProgram>$(ProjectDir)..\..\lib\NUnit\tools\nunit-console.exe</StartProgram>
<StartArguments>/nologo /noshadow /labels /wait $(AssemblyName).dll</StartArguments>
<StartWorkingDirectory>$(ProjectDir)$(OutputPath)</StartWorkingDirectory>
</PropertyGroup>
</Project>

@ -39,6 +39,7 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
using Google.ProtocolBuffers.Collections;
using Google.ProtocolBuffers.Compiler.PluginProto;
using Google.ProtocolBuffers.DescriptorProtos;
using Google.ProtocolBuffers.Descriptors;
@ -65,20 +66,9 @@ namespace Google.ProtocolBuffers.ProtoGen
return new Generator(options);
}
public void Generate()
public void Generate(CodeGeneratorRequest request, CodeGeneratorResponse.Builder response)
{
List<FileDescriptorSet> descriptorProtos = new List<FileDescriptorSet>();
foreach (string inputFile in options.InputFiles)
{
ExtensionRegistry extensionRegistry = ExtensionRegistry.CreateInstance();
CSharpOptions.RegisterAllExtensions(extensionRegistry);
using (Stream inputStream = File.OpenRead(inputFile))
{
descriptorProtos.Add(FileDescriptorSet.ParseFrom(inputStream, extensionRegistry));
}
}
IList<FileDescriptor> descriptors = ConvertDescriptors(options.FileOptions, descriptorProtos.ToArray());
IList<FileDescriptor> descriptors = ConvertDescriptors(options.FileOptions, request.ProtoFileList);
// Combine with options from command line
foreach (FileDescriptor descriptor in descriptors)
@ -99,6 +89,7 @@ namespace Google.ProtocolBuffers.ProtoGen
names.Add(file, true);
}
var filesToGenerate = new HashSet<string>(request.FileToGenerateList);
foreach (FileDescriptor descriptor in descriptors)
{
// Optionally exclude descriptors in google.protobuf
@ -106,7 +97,10 @@ namespace Google.ProtocolBuffers.ProtoGen
{
continue;
}
Generate(descriptor, duplicates);
if (filesToGenerate.Contains(descriptor.Name))
{
Generate(descriptor, duplicates, response);
}
}
}
@ -114,14 +108,20 @@ namespace Google.ProtocolBuffers.ProtoGen
/// Generates code for a particular file. All dependencies must
/// already have been resolved.
/// </summary>
private void Generate(FileDescriptor descriptor, bool duplicates)
private void Generate(FileDescriptor descriptor, bool duplicates, CodeGeneratorResponse.Builder response)
{
UmbrellaClassGenerator ucg = new UmbrellaClassGenerator(descriptor);
using (TextWriter textWriter = File.CreateText(GetOutputFile(descriptor, duplicates)))
var code = new StringBuilder();
var ucg = new UmbrellaClassGenerator(descriptor);
using (StringWriter textWriter = new StringWriter(code))
{
TextGenerator writer = new TextGenerator(textWriter, options.LineBreak);
ucg.Generate(writer);
}
response.AddFile(new CodeGeneratorResponse.Types.File.Builder
{
Name = GetOutputFile(descriptor, duplicates),
Content = code.ToString(),
}.Build());
}
private string GetOutputFile(FileDescriptor descriptor, bool duplicates)
@ -164,16 +164,8 @@ namespace Google.ProtocolBuffers.ProtoGen
/// </summary>
/// <exception cref="DependencyResolutionException">Not all dependencies could be resolved.</exception>
public static IList<FileDescriptor> ConvertDescriptors(CSharpFileOptions options,
params FileDescriptorSet[] descriptorProtos)
IList<FileDescriptorProto> fileList)
{
// Simple strategy: Keep going through the list of protos to convert, only doing ones where
// we've already converted all the dependencies, until we get to a stalemate
List<FileDescriptorProto> fileList = new List<FileDescriptorProto>();
foreach (FileDescriptorSet set in descriptorProtos)
{
fileList.AddRange(set.FileList);
}
FileDescriptor[] converted = new FileDescriptor[fileList.Count];
Dictionary<string, FileDescriptor> convertedMap = new Dictionary<string, FileDescriptor>();

File diff suppressed because it is too large Load Diff

@ -35,7 +35,9 @@
#endregion
using System;
using System.IO;
using System.Collections.Generic;
using Google.ProtocolBuffers.Compiler.PluginProto;
using Google.ProtocolBuffers.DescriptorProtos;
namespace Google.ProtocolBuffers.ProtoGen
@ -62,8 +64,33 @@ namespace Google.ProtocolBuffers.ProtoGen
return 1;
}
var request = new CodeGeneratorRequest.Builder();
foreach (string inputFile in options.InputFiles)
{
ExtensionRegistry extensionRegistry = ExtensionRegistry.CreateInstance();
CSharpOptions.RegisterAllExtensions(extensionRegistry);
using (Stream inputStream = File.OpenRead(inputFile))
{
var fileSet = FileDescriptorSet.ParseFrom(inputStream, extensionRegistry);
foreach (var fileProto in fileSet.FileList)
{
request.AddFileToGenerate(fileProto.Name);
request.AddProtoFile(fileProto);
}
}
}
Generator generator = Generator.CreateGenerator(options);
generator.Generate();
var response = new CodeGeneratorResponse.Builder();
generator.Generate(request.Build(), response);
if (response.HasError)
{
throw new Exception(response.Error);
}
foreach (var file in response.FileList)
{
File.WriteAllText(file.Name, file.Content);
}
return 0;
}
catch (Exception e)

@ -59,6 +59,7 @@
<Compile Include="ISourceGenerator.cs" />
<Compile Include="MessageFieldGenerator.cs" />
<Compile Include="MessageGenerator.cs" />
<Compile Include="PluginProtoFile.cs" />
<Compile Include="PrimitiveFieldGenerator.cs" />
<Compile Include="ProgramPreprocess.cs" />
<Compile Include="RepeatedEnumFieldGenerator.cs" />

@ -0,0 +1,76 @@
using Google.ProtocolBuffers.Compiler.PluginProto;
using Google.ProtocolBuffers.DescriptorProtos;
using System;
using System.Collections.Generic;
// Usage example:
// protoc.exe
// --plugin=path\to\protoc-gen-cs.exe
// --cs_out="-generated_code_attributes=true umbrella_namespace=TutorialProto :."
// --proto_path=.\protos\
// protos\tutorial\addressbook.proto
namespace Google.ProtocolBuffers.ProtoGen
{
public static class ProtocGenCs
{
internal static void Run(CodeGeneratorRequest request, CodeGeneratorResponse.Builder response)
{
var arguments = new List<string>();
foreach (var arg in request.Parameter.Split(' '))
{
var timmedArg = (arg ?? "").Trim();
if (!string.IsNullOrEmpty(timmedArg))
{
arguments.Add(timmedArg);
}
}
// Adding fake input file to make TryValidate happy.
arguments.Add(System.Reflection.Assembly.GetExecutingAssembly().Location);
GeneratorOptions options = new GeneratorOptions
{
Arguments = arguments
};
IList<string> validationFailures;
if (!options.TryValidate(out validationFailures))
{
response.Error += new InvalidOptionsException(validationFailures).Message;
return;
}
Generator generator = Generator.CreateGenerator(options);
generator.Generate(request, response);
}
public static int Main(string[] args)
{
// Hack to make sure everything's initialized
DescriptorProtoFile.Descriptor.ToString();
ExtensionRegistry extensionRegistry = ExtensionRegistry.CreateInstance();
CSharpOptions.RegisterAllExtensions(extensionRegistry);
CodeGeneratorRequest request;
var response = new CodeGeneratorResponse.Builder();
try
{
using (var input = Console.OpenStandardInput())
{
request = CodeGeneratorRequest.ParseFrom(input, extensionRegistry);
}
Run(request, response);
}
catch (Exception e)
{
response.Error += e.ToString();
}
using (var output = Console.OpenStandardOutput())
{
response.Build().WriteTo(output);
output.Flush();
}
return 0;
}
}
}

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<EnvironmentFlavor>CLIENTPROFILE</EnvironmentFlavor>
<EnvironmentTemplate>NET35</EnvironmentTemplate>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{250ADE34-82FD-4BAE-86D5-985FBE589C4B}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Google.ProtocolBuffers.ProtoGen</RootNamespace>
<AssemblyName>protoc-gen-cs</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\..\keys\Google.ProtocolBuffers.snk</AssemblyOriginatorKeyFile>
<StartupObject>Google.ProtocolBuffers.ProtoGen.ProtocGenCs</StartupObject>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\NET35\Debug</OutputPath>
<IntermediateOutputPath>obj\NET35\Debug\</IntermediateOutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<NoStdLib>true</NoStdLib>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\NET35\Release</OutputPath>
<IntermediateOutputPath>obj\NET35\Release\</IntermediateOutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<NoStdLib>true</NoStdLib>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
</PropertyGroup>
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="DescriptorUtil.cs" />
<Compile Include="EnumFieldGenerator.cs" />
<Compile Include="EnumGenerator.cs" />
<Compile Include="ExtensionGenerator.cs" />
<Compile Include="FieldGeneratorBase.cs" />
<Compile Include="IFieldSourceGenerator.cs" />
<Compile Include="ISourceGenerator.cs" />
<Compile Include="MessageFieldGenerator.cs" />
<Compile Include="MessageGenerator.cs" />
<Compile Include="PluginProtoFile.cs" />
<Compile Include="PrimitiveFieldGenerator.cs" />
<Compile Include="ProtocGenCs.cs" />
<Compile Include="RepeatedEnumFieldGenerator.cs" />
<Compile Include="RepeatedMessageFieldGenerator.cs" />
<Compile Include="RepeatedPrimitiveFieldGenerator.cs" />
<Compile Include="ServiceGenerator.cs" />
<Compile Include="DependencyResolutionException.cs" />
<Compile Include="Generator.cs" />
<Compile Include="GeneratorOptions.cs" />
<Compile Include="Helpers.cs" />
<Compile Include="InvalidOptionsException.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ServiceInterfaceGenerator.cs" />
<Compile Include="SourceGeneratorBase.cs" />
<Compile Include="SourceGenerators.cs" />
<Compile Include="UmbrellaClassGenerator.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ProtocolBuffers.Serialization\ProtocolBuffers.Serialization.csproj">
<Project>{231391af-449c-4a39-986c-ad7f270f4750}</Project>
<Name>ProtocolBuffers.Serialization</Name>
</ProjectReference>
<ProjectReference Include="..\ProtocolBuffers\ProtocolBuffers.csproj">
<Project>{6908BDCE-D925-43F3-94AC-A531E6DF2591}</Project>
<Name>ProtocolBuffers</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

@ -5,6 +5,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "proto", "proto", "{1F896D5C
..\protos\tutorial\addressbook.proto = ..\protos\tutorial\addressbook.proto
..\protos\google\protobuf\csharp_options.proto = ..\protos\google\protobuf\csharp_options.proto
..\protos\google\protobuf\descriptor.proto = ..\protos\google\protobuf\descriptor.proto
..\protos\google\protobuf\compiler\plugin.proto = ..\protos\google\protobuf\compiler\plugin.proto
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "unittest", "unittest", "{C8D3015A-EA39-4F03-AEEC-3FF1F2087A12}"
@ -88,6 +89,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks",
..\protos\benchmarks\google_speed.proto = ..\protos\benchmarks\google_speed.proto
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "protoc-gen-cs", "ProtoGen\protoc-gen-cs.csproj", "{250ADE34-82FD-4BAE-86D5-985FBE589C4B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "protoc-gen-cs.Test", "ProtoGen.Test\protoc-gen-cs.Test.csproj", "{C1024C9C-8176-48C3-B547-B9F6DF6B80A6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug_Silverlight|Any CPU = Debug_Silverlight|Any CPU
@ -174,6 +179,22 @@ Global
{E067A59D-9D0A-4A1F-92B1-38E4457241D1}.Release_Silverlight|Any CPU.ActiveCfg = Release|Any CPU
{E067A59D-9D0A-4A1F-92B1-38E4457241D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E067A59D-9D0A-4A1F-92B1-38E4457241D1}.Release|Any CPU.Build.0 = Release|Any CPU
{250ADE34-82FD-4BAE-86D5-985FBE589C4B}.Debug_Silverlight|Any CPU.ActiveCfg = Debug|Any CPU
{250ADE34-82FD-4BAE-86D5-985FBE589C4B}.Debug_Silverlight|Any CPU.Build.0 = Debug|Any CPU
{250ADE34-82FD-4BAE-86D5-985FBE589C4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{250ADE34-82FD-4BAE-86D5-985FBE589C4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{250ADE34-82FD-4BAE-86D5-985FBE589C4B}.Release_Silverlight|Any CPU.ActiveCfg = Release|Any CPU
{250ADE34-82FD-4BAE-86D5-985FBE589C4B}.Release_Silverlight|Any CPU.Build.0 = Release|Any CPU
{250ADE34-82FD-4BAE-86D5-985FBE589C4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{250ADE34-82FD-4BAE-86D5-985FBE589C4B}.Release|Any CPU.Build.0 = Release|Any CPU
{C1024C9C-8176-48C3-B547-B9F6DF6B80A6}.Debug_Silverlight|Any CPU.ActiveCfg = Debug|Any CPU
{C1024C9C-8176-48C3-B547-B9F6DF6B80A6}.Debug_Silverlight|Any CPU.Build.0 = Debug|Any CPU
{C1024C9C-8176-48C3-B547-B9F6DF6B80A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C1024C9C-8176-48C3-B547-B9F6DF6B80A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C1024C9C-8176-48C3-B547-B9F6DF6B80A6}.Release_Silverlight|Any CPU.ActiveCfg = Release|Any CPU
{C1024C9C-8176-48C3-B547-B9F6DF6B80A6}.Release_Silverlight|Any CPU.Build.0 = Release|Any CPU
{C1024C9C-8176-48C3-B547-B9F6DF6B80A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C1024C9C-8176-48C3-B547-B9F6DF6B80A6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -185,6 +206,7 @@ Global
{EE01ED24-3750-4567-9A23-1DB676A15610} = {C7B69674-7A51-4AC6-8674-0330BA742CE4}
{EEFFED24-3750-4567-9A23-1DB676A15610} = {C7B69674-7A51-4AC6-8674-0330BA742CE4}
{DD01ED24-3750-4567-9A23-1DB676A15610} = {C7B69674-7A51-4AC6-8674-0330BA742CE4}
{C1024C9C-8176-48C3-B547-B9F6DF6B80A6} = {C7B69674-7A51-4AC6-8674-0330BA742CE4}
{A31F5FB2-4FF3-432A-B35B-5CD203606311} = {75D5D25A-01A6-4594-957F-5993FB83F450}
{C7A4A435-2813-41C8-AA87-BD914BA5223D} = {0D7CDA8F-1BBF-4E0F-8D35-31AEA21A96E6}
{D7282E99-2DC3-405B-946F-177DB2FD2AE2} = {0D7CDA8F-1BBF-4E0F-8D35-31AEA21A96E6}

Loading…
Cancel
Save