Pergunta

Eu estou tentando usar o protobuf em um projeto C#, utilizando o protobuf-net, e estou querendo saber qual é a melhor maneira de organizar isso em um projeto do Visual Studio estrutura.

Quando manualmente usando o protogen ferramenta para gerar código em C#, a vida parece fácil, mas não se sente bem.

Eu gostaria .proto arquivo a ser considerado o principal arquivo de código-fonte, gerando C# ficheiros como um produto, mas antes o compilador C# se envolve.

As opções parecem ser:

  1. Ferramenta personalizada para proto ferramentas (embora eu não posso ver por onde começar lá)
  2. Pré-etapa de compilação (chamada protogen ou um arquivo de lote que faz isso)

Eu tenho lutado com 2), como ele continua me dando "O sistema não pode encontrar o arquivo especificado" se eu não usar caminhos absolutos (e eu não gosto de forçar projetos explicitamente ser localizado).

Existe uma convenção (ainda) para isso?


Editar: Com base na @jon comentários, eu repetida a pré-etapa de compilação e método utilizado este (protogen a localização codificado por agora), usando o catálogo de endereços, exemplo:

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

Edit2: Tendo @jon recomendação para minimizar o tempo de compilação por não processar a .proto arquivos se eles não mudaram, eu já bati em conjunto uma ferramenta básica para verificar para mim (isto pode, provavelmente, ser expandida para um full-Custom-ferramenta de Compilação):

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);
        }
    }
}

O meu pré-comando de compilação é agora (tudo em uma linha):

$(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
Foi útil?

Solução

Como uma extensão do código de Shaun, tenho o prazer de anunciar que protobuf-net agora tem integração do Visual Studio por meio de uma ferramenta personalizada. O instalador MSI está disponível no projeto página . Mais informação completa aqui: protobuf-net; agora com adicionado Orcas .

Visual Studio com protobuf-net como uma ferramenta personalizada

Outras dicas

Chamar uma etapa de pré-build mas usando variáveis ??do projeto (por exemplo $(ProjectPath)) para criar nomes de arquivo absolutos sem tê-los realmente em sua solução parece uma aposta razoável para mim.

Uma coisa que você pode querer considerar, com base na minha experiência passada de geradores de código: você pode querer escrever um wrapper para protogen que gera código para um local diferente, em seguida, verifica se o código recém-gerado é o mesmo que o antigo código, e não substituí-lo se assim for. Dessa forma Visual Studio vai perceber nada mudou e não forçar esse projeto a ser reconstruída -. Isso tem vezes corte build dramaticamente para mim no passado

Como alternativa, você poderia manter um hash MD5 do arquivo .proto a última vez protogen foi executado, e só executar protogen se o arquivo .proto mudou - ainda menos para fazer em cada build

Obrigado por levantar esta como uma questão embora -. Sugere claramente que eu deveria trabalhar para fora uma maneira de fazer este um passo fácil de pré-compilação para minha própria porta

Adicione o seguinte evento de pré-compilação para as configurações do projeto para gerar o arquivo C # apenas quando o arquivo .proto mudou. Basta substituir YourFile com o nome de nome base do seu arquivo .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 }

Isso funciona em qualquer versão recente do Visual Studio, ao contrário da ferramenta Custom-Desenvolver protobuf-net, que não suporta o Visual Studio 2012 ou Visual Studio 2013, de acordo com problemas 338 e 413 .

Adicione esta para o arquivo de projeto relevante.

Advantage, compilação incremental.

Desvantagem, você precisa editar manualmente ao adicionar arquivos.

<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>

bem, isso me deu uma idéia (algo sobre a reinventar a roda)...

  • crie simples de Makefile.mak, algo como
.SUFFIXES : .cs .proto

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

(obviamente, não se esqueça de substituir caminhos para protogen e csharp.xlst). IMPORTANTE - protogen\protogen.exe comando de partida do caractere de TABULAÇÃO, e não 8 espaços

  • Se você não deseja especificar os ficheiros necessários para construir o tempo todo, você pode usar algo como
.SUFFIXES : .cs .proto

all: mycs1.cs myotherfile.cs

.proto.cs:
    protogen\protogen.exe -i:$? -o:$@ -t:protogen\csharp.xlst
  • na pré-etapa de compilação para adicionar
cd $(ProjectDir) && "$(DevEnvDir)..\..\vc\bin\nmake" /NOLOGO -c -f Makefile.mak mycs1.cs myotherfile.cs

ou, se você tiver nmake no seu caminho, pode-se usar

cd $(ProjectDir) && nmake /NOLOGO -c -f Makefile.mak mycs1.cs myotherfile.cs

Anexei um invólucro Estúdio Custom Tool Visual rápida e suja ao redor ProtoGen.exe para a página do Google Code para este problema ( http://code.google.com/p/protobuf-net/issues/detail?id=39 ). Isso faz com que a adição de .proto arquivos para projetos C # extremamente fácil.

Veja o readme no anexo para mais informações.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top