Буферы протоколов в проектах C # с использованием protobuf-net - лучшие практики для генерации кода - PullRequest
16 голосов
/ 17 января 2009

Я пытаюсь использовать protobuf в проекте C #, используя protobuf-net, и мне интересно, как лучше всего организовать это в структуру проекта Visual Studio.

Когда вы вручную используете инструмент Protogen для генерации кода в C #, жизнь кажется простой, но не совсем правильной.

Я бы хотел, чтобы файл .proto считался основным файлом исходного кода, генерируя файлы C # как побочный продукт, но до того, как в него включился компилятор C #.

Возможны следующие варианты:

  1. Пользовательский инструмент для инструментов прото (хотя я не вижу, с чего начать)
  2. Шаг предварительной сборки (вызов протогена или пакетного файла, который делает это)

Я боролся с 2) выше, так как он продолжает давать мне «Системе не удается найти указанный файл», если я не использую абсолютные пути (и я не люблю принудительно определять местоположение проектов).

Есть ли соглашение (пока) для этого?


Edit: Основываясь на комментариях @ jon, я повторил метод шага перед сборкой и использовал его (на данный момент местоположение протогена жестко задано), используя пример адресной книги Google:

c:\bin\protobuf\protogen "-i:$(ProjectDir)AddressBook.proto" 
       "-o:$(ProjectDir)AddressBook.cs" -t:c:\bin\protobuf\csharp.xslt

Edit2: Принимая во внимание рекомендацию @ jon минимизировать время сборки, не обрабатывая файлы .proto, если они не изменились, я собрал основной инструмент для проверки (возможно, его можно расширить до полного инструмента Custom-Build):

using System;
using System.Diagnostics;
using System.IO;

namespace PreBuildChecker
{
    public class Checker
    {
        static int Main(string[] args)
        {
            try
            {
                Check(args);
                return 0;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return 1;
            }
        }

        public static void Check(string[] args)
        {
            if (args.Length < 3)
            {
                throw new ArgumentException(
                    "Command line must be supplied with source, target and command-line [plus options]");
            }

            string source = args[0];
            string target = args[1];
            string executable = args[2];
            string arguments = args.Length > 3 ? GetCommandLine(args) : null;

            FileInfo targetFileInfo = new FileInfo(target);
            FileInfo sourceFileInfo = new FileInfo(source);
            if (!sourceFileInfo.Exists) 
            {
                throw new ArgumentException(string.Format(
                    "Source file {0} not found", source));
            }

            if (!targetFileInfo.Exists || 
                sourceFileInfo.LastWriteTimeUtc > targetFileInfo.LastAccessTimeUtc)
            {
                Process process = new Process();
                process.StartInfo.FileName = executable;
                process.StartInfo.Arguments = arguments;
                process.StartInfo.ErrorDialog = true;

                Console.WriteLine(string.Format(
                     "Source newer than target, launching tool: {0} {1}",
                     executable,
                     arguments));
                process.Start();
            }
        }

        private static string GetCommandLine(string[] args)
        {
            string[] arguments = new string[args.Length - 3];
            Array.Copy(args, 3, arguments, 0, arguments.Length);
            return String.Join(" ", arguments);
        }
    }
}

Моя команда перед сборкой теперь (все в одной строке):

$(SolutionDir)PreBuildChecker\$(OutDir)PreBuildChecker 
    $(ProjectDir)AddressBook.proto 
    $(ProjectDir)AddressBook.cs 
    c:\bin\protobuf\protogen 
      "-i:$(ProjectDir)AddressBook.proto" 
      "-o:$(ProjectDir)AddressBook.cs" 
      -t:c:\bin\protobuf\csharp.xslt

Ответы [ 6 ]

8 голосов
/ 16 июля 2009

Как расширение кода Шона, я рад сообщить, что protobuf-net теперь имеет интеграцию с Visual Studio посредством специального инструмента. Установщик msi доступен на странице проекта . Более полная информация здесь: protobuf-net; теперь с добавленными Orcas .

Visual Studio with protobuf-net as a Custom Tool

8 голосов
/ 17 января 2009

Вызов шага перед сборкой, но с использованием переменных проекта (например, $(ProjectPath)) для создания абсолютных имен файлов без их фактического включения в ваше решение, мне показалось бы разумной ставкой.

Одна вещь, которую вы, возможно, захотите рассмотреть, основываясь на моем прошлом опыте генераторов кода: вы можете написать оболочку для protogen, которая генерирует код в другом месте, а затем проверяет, совпадает ли вновь сгенерированный код со старым код, и не перезаписывать его, если так. Таким образом, Visual Studio поймет, что ничего не изменилось, и не заставит этот проект перестраиваться - это сократило для меня время сборки резко в прошлом.

Кроме того, вы можете сохранить хэш md5 .proto-файла при последнем запуске protogen и запускать protogen только в том случае, если изменился файл .proto - еще меньше при каждой сборке!

Спасибо за то, что подняли этот вопрос как вопрос - он явно предлагает мне найти способ сделать этот шаг простым шагом перед сборкой для моего собственного порта.

6 голосов
/ 17 сентября 2015

Добавьте это в соответствующий файл проекта.

Преимущество, инкрементная сборка.

Недостаток, вам нужно редактировать вручную при добавлении файлов.

<ItemGroup>
    <Proto Include="Person.proto" />
    <Compile Include="Person.cs">
        <DependentUpon>Person.proto</DependentUpon>
    </Compile>
</ItemGroup>
<PropertyGroup>
    <CompileDependsOn>ProtobufGenerate;$(CompileDependsOn)</CompileDependsOn>
</PropertyGroup>
<Target Name="ProtobufGenerate" Inputs="@(Proto)" Outputs="@(Proto->'$(ProjectDir)%(Filename).cs')">
    <ItemGroup>
        <_protoc Include="..\packages\Google.Protobuf.*\tools\protoc.exe" />
    </ItemGroup>
    <Error Condition="!Exists(@(_protoc))" Text="Could not find protoc.exe" />
    <Exec Command="&quot;@(_protoc)&quot; &quot;--csharp_out=$(ProjectDir.TrimEnd('\'))&quot; @(Proto->'%(Identity)',' ')" WorkingDirectory="$(ProjectDir)" />
</Target>
6 голосов
/ 13 декабря 2012

Добавьте следующее событие предварительной сборки в настройки проекта, чтобы генерировать файл C # только после изменения файла .proto. Просто замените YourFile на имя базового имени вашего .proto файла.

cd $(ProjectDir) && powershell -Command if (!(Test-Path YourFile.proto.cs) -or (Get-Item YourFile.proto).LastWriteTimeUtc -gt (Get-Item YourFile.proto.cs).LastWriteTimeUtc) { PathToProtoGen\protogen -i:YourFile.proto -o:YourFile.proto.cs }

Это работает в любой последней версии Visual Studio, в отличие от инструмента Custom-Build protobuf-net, который не поддерживает Visual Studio 2012 или Visual Studio 2013, в соответствии с проблемами 338 и 413 .

5 голосов
/ 22 мая 2009

ну, это дало мне идею (что-то о изобретении колеса) ...

  • создайте простой Makefile.mak, что-то вроде
.SUFFIXES : .cs .proto

.proto.cs:
    protogen\protogen.exe -i:$? -o:$@ -t:protogen\csharp.xlst

(очевидно, не забудьте заменить пути к protogen и csharp.xlst). ВАЖНО - команда protogen \ protogen.exe, начинающаяся с символа табуляции, а не 8 пробелов

  • Если вы не хотите указывать файлы, необходимые для постоянной сборки, вы можете использовать что-то вроде
.SUFFIXES : .cs .proto

all: mycs1.cs myotherfile.cs

.proto.cs:
    protogen\protogen.exe -i:$? -o:$@ -t:protogen\csharp.xlst
  • на этапе предварительной сборки, чтобы добавить
cd $(ProjectDir) && "$(DevEnvDir)..\..\vc\bin\nmake" /NOLOGO -c -f Makefile.mak mycs1.cs myotherfile.cs

или, если у вас есть nmake на вашем пути, можно использовать

cd $(ProjectDir) && nmake /NOLOGO -c -f Makefile.mak mycs1.cs myotherfile.cs
2 голосов
/ 24 июня 2009

Я приложил быструю и грязную оболочку Visual Studio Custom Tool вокруг ProtoGen.exe к странице кода Google для этой проблемы (http://code.google.com/p/protobuf-net/issues/detail?id=39).. Это делает добавление файлов .proto в проекты C # чрезвычайно простым.

См. Файл readme во вложении для получения дополнительной информации.

...