Protobuf -Net을 사용한 C# 프로젝트의 프로토콜 버퍼 - 코드 생성 모범 사례
-
19-08-2019 - |
문제
C# 프로젝트에서 Protobuf를 사용하여 Protobuf-Net을 사용하려고 노력하고 있으며이를 Visual Studio Project 구조로 구성하는 가장 좋은 방법이 무엇인지 궁금합니다.
프로토겐 도구를 수동으로 사용하여 C#에 코드를 생성 할 때는 Life가 쉬운 것처럼 보이지만 기분이 좋지 않습니다.
.proto 파일이 기본 소스 코드 파일로 간주되어 C# 파일을 부산물로 생성하지만 C# 컴파일러가 참여하기 전에.
옵션은 다음과 같습니다.
- 프로토 도구를위한 맞춤형 도구 (어디서부터 시작 해야할지 볼 수는 없지만)
- 사전 건축 단계 (Protogen 또는 배치 파일 호출)
나는 절대 경로를 사용하지 않는 한 "시스템이 지정된 파일을 찾을 수 없다"는 "시스템이 지정된 파일을 찾을 수 없다"는 위의 2)로 고생했다 (그리고 프로젝트가 명시 적으로 위치하도록 강요하는 것을 좋아하지 않는다).
이것에 대한 컨벤션이 있습니까?
편집하다:@Jon의 의견을 바탕으로 Google의 주소 북 예제를 사용하여 건축 사전 단계 방법을 다시 만들고 이것 (현재로서는 Protogen의 위치 하드 코드)을 사용했습니다.
c:\bin\protobuf\protogen "-i:$(ProjectDir)AddressBook.proto"
"-o:$(ProjectDir)AddressBook.cs" -t:c:\bin\protobuf\csharp.xslt
edit2 :.proto 파일이 변경되지 않은 경우 빌드 타임을 최소화하기 위해 @Jon의 권장 사항을 취득한 후, 나는 나를 확인하는 기본 도구를 마련했습니다 (아마도 전체 사용자 정의 구축 도구로 확장 될 수 있음).
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
해결책
Shaun 코드의 확장으로 Protobuf-Net은 이제 사용자 정의 도구를 통해 Visual Studio 통합을 가지고 있음을 발표하게되어 기쁩니다. MSI 설치 프로그램은 프로젝트 페이지. 보다 완전한 정보는 다음과 같습니다. protobuf-net; 이제 추가 오크가 있습니다.
다른 팁
사전 건축 단계를 호출하지만 프로젝트 변수를 사용합니다 (예 : $(ProjectPath)
) 실제로 솔루션에 들어 가지 않고 절대 파일 이름을 만드는 것은 나에게 합리적인 내기처럼 보일 것입니다.
코드 생성기의 과거 경험을 바탕으로 고려해야 할 한 가지 : 다른 위치에 코드를 생성하는 Protogen 용 래퍼를 작성하고 새로 생성 된 코드가 이전 코드와 동일하고 동일한 지 확인합니다. 그렇다면 그것을 덮어 쓰지 않습니다. 그런 식으로 Visual Studio는 아무것도 변경되지 않았고 프로젝트가 재건되지 않도록 강요하지 않을 것입니다 - 이것은 빌드 타임을 줄였습니다. 극적으로 과거에 나를 위해.
또는 마지막으로 Protogen이 실행 된 경우 .proto 파일의 MD5 해시를 유지하고 .proto 파일이 변경된 경우에만 프로토 겐 만 실행할 수 있습니다. 각 빌드에서 수행 할 수 없습니다!
그래도 이것을 질문으로 제기해 주셔서 감사합니다. 이는 이것을 내 포트를위한 쉬운 사전 건설 단계로 만들 수있는 방법을 알아야합니다.
.proto 파일이 변경된 경우에만 C# 파일을 생성하기 위해 프로젝트 설정에 다음 사전 제작 이벤트를 추가하십시오. 그냥 교체하십시오 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 2012 또는 Visual Studio 2013을 지원하지 않는 Protobuf-Net Custom-Build Tool과 달리 최근 버전의 Visual Studio에서 작동합니다. 338 그리고 413.
이것을 관련 프로젝트 파일에 추가하십시오.
장점, 증분 빌드.
단점은 파일을 추가 할 때 수동으로 편집해야합니다.
<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=""@(_protoc)" "--csharp_out=$(ProjectDir.TrimEnd('\'))" @(Proto->'%(Identity)',' ')" WorkingDirectory="$(ProjectDir)" />
</Target>
글쎄, 그것은 나에게 아이디어를 주었다 (바퀴를 재창조하는 것에 관한 것) ...
- 간단한 makefile.mak을 만들어냅니다
.SUFFIXES : .cs .proto .proto.cs: protogen\protogen.exe -i:$? -o:$@ -t:protogen\csharp.xlst
(분명히, Protogen 및 Csharp.xlst 로의 경로를 대체하는 것을 잊지 마십시오). 중요 - protogen protenge.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
이 문제에 대한 Google 코드 페이지에 Protogen.exe 주변의 빠르고 더러운 비주얼 스튜디오 사용자 정의 래퍼를 첨부했습니다 (http://code.google.com/p/protobuf-net/issues/detail?id=39). 따라서 C# 프로젝트에 .proto 파일을 추가하는 것은 매우 쉽습니다.
자세한 내용은 첨부 파일의 readme를 참조하십시오.