xref: /aosp_15_r20/external/grpc-grpc/src/csharp/BUILD-INTEGRATION.md (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1# Protocol Buffers/gRPC Codegen Integration Into .NET Build
2
3The [Grpc.Tools](https://www.nuget.org/packages/Grpc.Tools) NuGet package provides C# tooling support for generating C# code from `.proto` files in `.csproj` projects:
4* It contains protocol buffers compiler and gRPC plugin to generate C# code.
5* It can be used in building both grpc-dotnet projects and legacy c-core C# projects.
6
7Using `Grpc.Tools` in `.csproj` files is described below. Other packages providing the runtime libraries for gRPC are described elsewhere.
8
9## Getting Started
10
11The package [Grpc.Tools](https://www.nuget.org/packages/Grpc.Tools) is used automatically to generate the C# code for protocol buffer messages and gRPC service stubs from
12`.proto` files. These files:
13* are generated on an as-needed basis each time the project is built.
14* aren't added to the project or checked into source control.
15* are a build artifact usually contained in the obj directory.
16
17This package is optional. You may instead choose to generate the C# source files from
18`.proto` files by running the `protoc` compiler manually or from a script.
19However this package helps to simplify generating the C# source files by
20integrating the code generation into the build process. It can be used when building both
21the server and client projects, and by both c-core C# projects and grpc-dotnet projects:
22* The `Grpc.AspNetCore` metapackage already includes a reference to `Grpc.Tools`.
23* gRPC for .NET client projects and projects using `Grpc.Core` need to reference `Grpc.Tools` explicity if you want code generation for those projects
24
25`Grpc.Tools` is only used at build-time and has no runtime components.
26It should be marked with `PrivateAssets="All"` to prevent it from being included at runtime, e.g.
27```xml
28<PackageReference Include="Grpc.Tools" Version="2.50.0">
29  <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
30  <PrivateAssets>all</PrivateAssets>
31</PackageReference>
32```
33
34Support is provided for the following platforms:
35* Windows (x86, x64, and arm64 via using the x86 binaries)
36* MacOS (x64 and arm64 via using the x64 binaries)
37* Linux (x86, x64, and arm64)
38
39You may still use the MSBuild integration provided by `Grpc.Tools` for other architectures provided you can supply the codegen binaries for that platform/architecture.
40See [Using Grpc.Tools with unsupported architectures](#unsupported-arch) below.
41
42## Adding `.proto` files to a project
43
44To add `.proto` files to a project edit the project’s `.csproj` file and add an item group with a `<Protobuf>` element that refers to the `.proto` file, e.g.
45
46```xml
47<ItemGroup>
48    <Protobuf Include="Protos\greet.proto" />
49</ItemGroup>
50```
51
52Wildcards can be used to select several `.proto` files, e.g.
53
54```xml
55<ItemGroup>
56    <Protobuf Include="**\*.proto" />
57</ItemGroup>
58```
59
60By default, a `<Protobuf>` reference generates gRPC client and a service base class from the `service` definitions in the `.proto` files.
61The `GrpcServices` attribute can be used to limit C# asset generation. See the reference section below for all
62options. E.g. to only generate client code:
63
64```xml
65<ItemGroup>
66    <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
67</ItemGroup>
68```
69
70For `.proto` files that are outside of the project directory a link can be added so that the files are visible in Visual Studio. E.g.
71
72```xml
73<ItemGroup>
74   <Protobuf Include="..\Proto\aggregate.proto" GrpcServices="Client" Link="Protos\aggregate.proto"/>
75   <Protobuf Include="..\Proto\greet.proto" GrpcServices="None" Link="Protos\greet.proto"/>
76   <Protobuf Include="..\Proto\count.proto" GrpcServices="None" Link="Protos\count.proto"/>
77</ItemGroup>
78```
79
80For more examples see the example project files in GitHub: https://github.com/grpc/grpc-dotnet/tree/master/examples
81
82## Sharing `.proto` files between multiple projects (in the same VS solution)
83
84It's common to want to share `.proto` files between projects. For example, a gRPC client
85and gRPC server share the same contract. It is preferable to share contracts without
86copying `.proto` files because copies can go out of sync over time.
87
88There are a couple of ways to use `.proto` files in multiple projects without duplication:
89
90* Sharing `.proto` files between projects with MSBuild links.
91* Generating code in a class library and sharing the library.
92
93### Sharing `.proto` with MSBuild links
94
95`.proto` files can be placed in a shared location and referenced by multiple projects
96using MSBuild's [`Link` or `LinkBase` settings](https://learn.microsoft.com/visualstudio/msbuild/common-msbuild-item-metadata).
97
98```xml
99<ItemGroup>
100   <Protobuf Include="..\Protos\greet.proto" GrpcServices="None" Link="Protos\greet.proto"/>
101</ItemGroup>
102```
103
104In the example above, `greet.proto` is in a shared `Protos` directory outside
105the project directory. Multiple projects can reference the proto file.
106
107### Generating code in a class library
108
109Create a class library that references `.proto` files and contains generated code. The other
110projects in the solution can then reference this shared class library instead of each project
111having to compile the same `.proto` files.
112
113The advantages of this are:
114- The `.proto` only need to be compiled once.
115- It prevents some projects getting multiple definitions of the same generated code, which can in turn break the build.
116
117There are a couple of examples in GitHub:
118- The [Liber example](https://github.com/grpc/grpc-dotnet/tree/master/examples#liber)
119  demonstrates how common protocol buffers messages can be compiled once and used in other projects:
120  - The *Common* project creates a class library that includes the generates messages contained in `common.proto`
121  - The *Client* and *Server* projects reference the *Common* project.
122  - They do not need to recompile `common.proto` as those .NET types are already in
123    the *Common* class library.
124  - They do however each generate their own gRPC client or server code as both have a
125    `<Protobuf>` reference for `greet.proto`.  The *Client* and *Server* projects each having their own version of `greet.proto` is OK since they don't reference each other - they only reference the shared *Common* class library.
126
127- The [RouteGuide example](https://github.com/grpc/grpc/tree/v1.46.x/examples/csharp/RouteGuide)
128  demonstrates how the gRPC client and server code can be generated once and used in other
129  projects:
130  - **Note:** this example uses the *legacy c-core C#* packages, but the principles are the same
131    for *gRPC for .NET* projects.
132  - The *RouteGuide* project has a `<Protobuf>` reference to `route_guide.proto` and
133    generates both the gRPC client and server code.
134  - The *RouteGuideClient* and *RouteGuideServer* projects reference the *RouteGuide* project.
135  - They do not need any `<Protobuf>` references since the code has already been
136    generated in the *RouteGuide* project.
137
138
139# Reference
140
141## Protobuf item metadata reference
142
143The following metadata are recognized on the `<Protobuf>` items.
144
145| Name           | Default   | Value                | Synopsis                         |
146|----------------|-----------|----------------------|----------------------------------|
147| Access         | `public`  | `public`, `internal`               | Generated class access           |
148| AdditionalProtocArguments | | arbitrary cmdline arguments | Extra command line flags passed to `protoc` command. To specify multiple arguments use semi-colons (;) to separate them. See example below |
149| ProtoCompile   | `true`    | `true`, `false`                    | If `false`, don't invoke `protoc` to generate code. |
150| ProtoRoot      | See notes | A directory                        | Common root for set of files     |
151| CompileOutputs | `true`    | `true`, `false`                    | If `false`, C# code will be generated, but it won't be included in the C# build. |
152| OutputDir      | See notes | A directory                        | Directory for generated C# files with protobuf messages |
153| OutputOptions  | | arbitrary options                  | Extra options passed to C# codegen as `--csharp_opt=opt1,opt2` |
154| GrpcOutputDir  | See notes | A directory                        | Directory for generated gRPC stubs    |
155| GrpcOutputOptions | | arbitrary options                  | Extra options passed to gRPC codegen as `--grpc_opt=opt1,opt2` |
156| GrpcServices   | `Both`    | `None`, `Client`, `Server`, `Both` | Generated gRPC stubs             |
157| AdditionalImportDirs | See notes | Directories                        | Specify additional directories in which to search for imports `.proto` files |
158
159__Notes__
160
161* __ProtoRoot__
162For files _inside_ the project directory or its subdirectories, `ProtoRoot` is set by default to the
163project directory.
164
165    For files _outside_ of the project directory, the value
166is set to the file's containing directory name, individually per file. If you
167include a subtree of `.proto` files that lies outside of the project directory, you
168need to set `ProtoRoot`. There is an example of this below. The path in
169this variable is relative to the project directory.
170
171* __OutputDir__
172The default value is the value of the property
173`Protobuf_OutputPath`. This property, in turn, unless you set it in your
174project, will be set to the value of the standard MSBuild property
175`IntermediateOutputPath`, which points to the location of compilation object
176outputs, such as `"obj/Release/netstandard1.5/"`. The path in this property is
177considered relative to the project directory.
178
179* __GrpcOutputDir__
180Unless explicitly set, will follow `OutputDir` for any given file.
181
182* __Access__
183Sets generated class access on _both_ generated message and gRPC stub classes.
184
185* __AdditionalProtocArguments__
186Pass additional commandline arguments to the `protoc` command being invoked.
187Normally this option should not be used, but it exists for scenarios when you need to pass
188otherwise unsupported (e.g. experimental) flags to protocol buffer compiler.
189
190* __OutputOptions__
191Pass additional C# code generation options to `protoc` in the form `--csharp_opt=opt1,opt2`. See [C#-specific options](https://protobuf.dev/reference/csharp/csharp-generated/#compiler_options) for possible values.
192
193* __GrpcOutputOptions__
194Pass additional options to the `grpc_csharp_plugin` in form of the `--grpc_opt` flag.
195Normally this option should not be used as its values are already controlled by `Access`
196and `GrpcServices` metadata, but it might be useful in situations where you want
197to explicitly pass some otherwise unsupported (e.g. experimental) options to the
198`grpc_csharp_plugin`.
199
200* __AdditionalImportDirs__
201Specify additional directories in which to search for imports in `.proto` files. The directories are searched in the order given. You may specify directories _outside_ of the
202project directory. The directories are passed to the `protoc` code generator via the `-I/--proto_path` option
203together with `Protobuf_StandardImportsPath` and `ProtoRoot` directories.
204
205__Specifying multiple values in properties__
206
207Some properties allow you to specify multiple values in a list. The items in a list need to
208be separated by semi-colons (;). This is the syntax that MsBuild uses for lists.
209
210The properties that can have lists of items are: `OutputOptions`, `AdditionalProtocArguments`,
211 `GrpcOutputOptions`, `AdditionalImportDirs`
212
213Example: to specify two additional arguments: `--plugin=protoc-gen-myplugin=D:\myplugin.exe --myplugin_out=.`
214
215```xml
216  <ItemGroup>
217    <Protobuf Include="proto_root/**/*.proto" ProtoRoot="proto_root"
218              OutputDir="%(RelativeDir)" CompileOutputs="false"
219              AdditionalProtocArguments="--plugin=protoc-gen-myplugin=D:\myplugin.exe;--myplugin_out=." />
220  </ItemGroup>
221```
222
223## `grpc_csharp_plugin` command line options
224
225Under the hood, the `Grpc.Tools` build integration invokes the `protoc` and `grpc_csharp_plugin` binaries
226to perform code generation. Here is an overview of the available `grpc_csharp_plugin` options:
227
228| Name            | Default   | Synopsis                                                 |
229|---------------- |-----------|----------------------------------------------------------|
230| no_client       | off       | Don't generate the client stub                           |
231| no_server       | off       | Don't generate the server-side stub                      |
232| internal_access | off       | Generate classes with "internal" visibility              |
233| file_suffix     | Grpc.cs   | The suffix that will get appended to the name of the generated file. **Can only be used on the command line.** |
234| base_namespace | none       | *Experimental - may change or be removed.* Same as `base_namespace` for `protoc` [C# options](https://protobuf.dev/reference/csharp/csharp-generated/#compiler_options) .  **Can only be used on the command line.** |
235
236To use these options with `Grpc.Tools` specify them in the __GrpcOutputOptions__
237metadata in the `<Protobuf>` item.
238
239Notes:
240- `file_suffix` and `base_namespace` should not be used with `Grpc.Tools`. Using them will break the build.
241
242- using `base_namespace` changes the algorithm for the generated file names to align it with the algorithm used by `protoc`.
243
244  This only affects files with punctuation or numbers in the name. E.g. `hello.world2d.proto` now generates file `HelloWorld2DGrpc.cs` instead of `Hello.world2dGrpc.cs`
245
246To use these options on the command line specify them with the `--grpc_opt`
247option.
248
249Code generated by `protoc` is independent of the plugin and you may also need to specify C# options for this with `--csharp_opt`.
250These are [documented here](https://protobuf.dev/reference/csharp/csharp-generated/#compiler_options).
251
252 e.g.:
253
254```bash
255protoc --plugin=protoc-gen-grpc=grpc_csharp_plugin \
256    --csharp_out=OUT_DIR \
257    --csharp_opt=base_namespace=Example \
258    --grpc_out=OUT_DIR \
259    --grpc_opt=no_server,base_namespace=Example \
260    -I INCLUDE_DIR foo.proto
261```
262## Environment Variables
263
264Environment variables can be set to change the behavior of `Grpc.Tools` - setting the CPU architecture or operating system, or using custom built protocol buffers compiler and gRPC plugin.
265
266| Name                | Synopsis                                                                      |
267|---------------------|-------------------------------------------------------------------------------|
268|`PROTOBUF_TOOLS_OS`  | Operating system version of the tools to use: `linux`, `macosx`, or `windows` |
269|`PROTOBUF_TOOLS_CPU` | CPU architecture version of the tools to use: `x86`, `x64`, or `arm64`        |
270|`PROTOBUF_PROTOC`    | Full path to the protocol buffers compiler                                    |
271|`GRPC_PROTOC_PLUGIN` | Full path to the grpc_csharp_plugin                                           |
272
273For example, to use a custom built protoc compiler and grpc_csharp_plugin:
274```bash
275export PROTOBUF_PROTOC=$my_custom_build/protoc
276export GRPC_PROTOC_PLUGIN=$my_custom_build/grpc_csharp_plugin
277dotnet build myproject.csproj
278```
279
280## MSBuild Properties
281
282You can set some Properties in your project file or on the MSBuild command line. The
283following properties change the behavior of `Grpc.Tools`:
284
285| Name                | Synopsis                                                                      |
286|---------------------|-------------------------------------------------------------------------------|
287| `Protobuf_ToolsOs`  | Same as `PROTOBUF_TOOLS_OS` environment variable                              |
288| `Protobuf_ToolsCpu` | Same as `PROTOBUF_TOOLS_CPU` environment variable                             |
289| `Protobuf_ProtocFullPath` | Same as `PROTOBUF_PROTOC` environment variable                          |
290| `gRPC_PluginFullPath` | Same as `GRPC_PROTOC_PLUGIN` environment variable                           |
291| `Protobuf_NoWarnMissingExpected` | Default: `false`. If `true` then no warnings are given if expected files not generated. See example below for an explanation. |
292| `Protobuf_OutputPath`| Default: `IntermediateOutputPath` - ususally the `obj` directory. Sets the default value for `OutputDir` on `<Protobuf>` items.|
293| `EnableDefaultProtobufItems` | Default: `false`. If `true` then `.proto` files under the project are automatically included without the need to specify any `<Protobuf>` items. |
294| `Protobuf_StandardImportsPath` | The path for protobuf's [well known types](https://protobuf.dev/reference/protobuf/google.protobuf/) included in the NuGet package. It is automcatically passed to `protoc`  via the `-I/--proto_path` option. |
295
296# Scenarios and Examples
297
298For other examples see also the `.csproj` files in the examples in GitHub:
299* [grpc-dotnet examples](https://github.com/grpc/grpc-dotnet/tree/master/examples)
300* [`Grpc.Core` examples](https://github.com/grpc/grpc/tree/v1.46.x/examples/csharp)
301
302Quick links to the examples below:
303
304* [ProtoRoot - Common root for one or more `.proto` files](#ProtoRoot)
305* [AdditionalImportDirs - Setting location of imported `.proto` files](#AdditionalImportDirs)
306* [GrpcServices - Generating gRPC services and protocol buffers messages](#grpcservices)
307* [Automatically including `.proto` files](#autoinclude)
308* [Generate proto and gRPC C# sources from .proto files (no C# compile)](#nocompile)
309* [Visual Studio: setting per-file `.proto` file options](#visualstudio)
310* [Bypassing Grpc.Tools to run the protocol buffers compiler explicitly](#compiler)
311* [Using Grpc.Tools with unsupported architectures](#unsupported-arch)
312* [Including `.proto` files in NuGet packages](#proto-only-nuget)
313
314---
315## <a name="ProtoRoot"></a>ProtoRoot - Common root for one or more `.proto` files
316
317`ProtoRoot` specifies a common directory that is an ancestor for a set of `.proto` files.
318
319It has two purposes:
320* working out relative directories to preserve the structure when generating `.cs` files
321* adding a directory to be searched for imported `.proto` files
322
323These are explained in an example below.
324
325For `.proto` files under the project directory `ProtoRoot` is by default set to `.`.
326It can also be explicitly set.
327
328For `.proto` files outside of the project the value is set to the file's containing directory name.
329If you include a subtree of `.proto` files then you must set `ProtoRoot` to give the
330parent of the directory tree.
331
332In either case if you are importing a `.proto` file from within another file then you should set
333`ProtoRoot` so that the import paths can be found. (See also `AdditionalImportDirs` below.)
334
335Generated files in the output directory will have the same directory structure as the
336`.proto` files under `ProtoRoot`.
337
338By default the output directory for generated files is `obj\CONFIGURATION\FRAMEWORK\` (e.g. `obj\Debug\net6.0\`) unless `OutputDir` or `GrpcOutputDir` are specified.
339### Example use of `ProtoRoot`
340Specifying:
341```xml
342<Protobuf Include="Protos\Services\**\*.proto"
343          ProtoRoot="Protos" />
344<Protobuf Include="Protos\Messages\**\*.proto"
345          ProtoRoot="Protos"
346          GrpcServices="None" />
347<Protobuf Include="..\OutsideProjectProtos\**\*.proto"
348          ProtoRoot="..\OutsideProjectProtos" />
349```
350for files:
351```
352	ProjectFolder\Protos\Services\v1\hello.proto
353	ProjectFolder\Protos\Services\v2\hello.proto
354	ProjectFolder\Protos\Messages\v1\message.proto
355	..\OutsideProjectProtos\MyApi\alpha.proto
356	..\OutsideProjectProtos\MyApi\beta.proto
357```
358will generate files:
359```
360  ProjectFolder\obj\Debug\net6.0\Services\v1\Hello.cs
361  ProjectFolder\obj\Debug\net6.0\Services\v1\HelloGrpc.cs
362  ProjectFolder\obj\Debug\net6.0\Services\v2\Hello.cs
363  ProjectFolder\obj\Debug\net6.0\Services\v2\HelloGrpc.cs
364  ProjectFolder\obj\Debug\net6.0\Messages\v1\Message.cs
365  ProjectFolder\obj\Debug\net6.0\MyApi\Alpha.cs
366  ProjectFolder\obj\Debug\net6.0\MyApi\AlphaGrpc.cs
367  ProjectFolder\obj\Debug\net6.0\MyApi\Beta.cs
368  ProjectFolder\obj\Debug\net6.0\MyApi\BetaGrpc.cs
369
370```
371Things to notes:
372* the directory structures under `ProjectFolder\Protos\` and `..\OutsideProjectProtos\` are mirrored in the output directory.
373* the import search paths passed to `protoc` via `-I/--proto_path` option will include
374 `ProjectFolder\Protos` and `..\OutsideProjectProtos`
375---
376## <a name="AdditionalImportDirs"></a>AdditionalImportDirs - Setting location of imported `.proto` files
377
378In addition to specifying `ProtoRoot` other import directories can be specified for
379directories to search when importing `.proto` files by specifying `AdditionalImportDirs`
380and provide a list of directories. The directories are searched in the order given.
381
382You would use this when you want to import `.proto` files that you don't need to
383separately compile as they are only used in import statements. E.g.:
384
385```xml
386  <Protobuf Include="protos/*.proto"
387            ProtoRoot="protos"
388            AdditionalImportDirs="/folder/protos/mytypes/;/another/folder/"
389      ... />
390```
391
392Note: The path for protobuf's [well known types](https://protobuf.dev/reference/protobuf/google.protobuf/) is automatically included. E.g. the `import` below will work without having to explicity specifying the path in `AdditionalImportDirs`:
393```protobuf
394import "google/protobuf/wrappers.proto";
395```
396---
397## <a name="grpcservices"></a>GrpcServices - Generating gRPC services and protocol buffers messages
398The protocol buffers files (`.proto` files) define both the service interface and the
399structure of the payload messages.
400
401Two `.cs` file can be generated from a `.proto` file. For example, if the `.proto` file
402is `myfile.proto` then the two possible files are:
403* `Myfile.cs` - contains the generated code for protocol buffers messages
404* `MyfileGrpc.cs`  - contains the generated code for gRPC client and/or server
405
406When a `.proto` file contains service definitions the protocol buffers compiler calls
407the gRPC plugin to generate gRPC client and/or server stub code. Whether or not the `*Grpc.cs` file
408is generated and what it contains is controlled by the `GrpcServices` metadata
409on the `<Protobuf>` item.
410
411* `GrpcServices="Both"` (the default) - `Myfile.cs` and `MyfileGrpc.cs` generated
412* `GrpcServices="None"` - just `Myfile.cs` generated
413* `GrpcServices="Client"` - `Myfile.cs` and `MyfileGrpc.cs` (just client code)
414* `GrpcServices="Server"` - `Myfile.cs` and `MyfileGrpc.cs` (just server code)
415
416However when a `.proto` **does not file contains any service definitions** but only contains
417message definitions then an empty (zero length) `MyfileGrpc.cs` may still be created
418by `Grpc.Tools` unless the `.proto` file is specified with `GrpcServices="None"` in the project file.
419
420This is because `Grpc.Tools` has no way of knowing in advanced of running the protocol buffers
421compiler whether a `.proto` file has a service clause. It creates the empty files as a marker
422for incremental builds so that the `.proto` files are not unnecessarily recompiled. Empty files
423are not a problem on a small project but you may wish to avoid them on a larger project.
424
425Therefore it is better to explicitly mark files with the correct `GrpcServices` metadata if you can. For
426example:
427
428```xml
429<ItemGroup>
430  <Protobuf Include="**/*.proto" GrpcServices="None" />
431  <Protobuf Update="**/hello/*.proto;**/bye/*.proto" GrpcServices="Both" />
432</ItemGroup>
433```
434In the above example all `.proto` files are compiled with `GrpcServices="None"`, except for `.proto`
435files in subdirectories on any tree level named `hello` and `bye`, which will take
436`GrpcServices="Both"`. Note the use of the `Update` attribute instead of `Include` - otherwise
437the files would be added twice.
438
439Another example would be the use of globbing if your service `.proto` files are named according
440to a pattern, for example `*_services.proto`. In this case the `Update` attribute can be written
441as `Update="**/*_service.proto"` to set the attribute `GrpcServices="Both"` only on these files.
442
443### Seeing a warning about a missing expected file
444
445You will see the warning message:
446 ```
447 Some expected protoc outputs were not generated
448 ```
449 if all these are true:
450 * the location for the generated files is configured to a directory outside of the project, e.g. `OutputDir="..\outside-project\"`
451 * `*Grpc.cs` files have not been created because the `.proto` file does not contain a
452service definintion
453* you have not specified `GrpcServices="None"`
454
455This is because `Grpc.Tools` only creates empty `*Grpc.cs` files in directories
456within the project (such as the intermediate `obj` directory). Empty files are not created
457outside of the project directory so as not to pollute non-project directories.
458
459This warning can be suppressed by setting the MSBuild property:
460```xml
461<PropertyGroup>
462  <Protobuf_NoWarnMissingExpected>true</Protobuf_NoWarnMissingExpected>
463</PropertyGroup>
464```
465however it is better to set `GrpcServices="None"` on the `.proto` files affected to avoid
466unnecessary rebuilds.
467
468
469---
470## <a name="autoinclude"></a>Automatically including `.proto` files
471
472For SDK projects it is possible to automatically include `.proto` files found in the project
473directory or sub-directories, without having to specify them with a `<Protobuf>` item.
474To do this the property `EnableDefaultProtobufItems` has be set to `true` in the project file or on the MSBuild command line.
475
476It is recommended that you do not rely on automatic inclusion of `.proto` files except for
477the simplest of projects since it does not allow you to control other settings such as
478`GrpcServices`.
479
480By default `EnableDefaultProtobufItems` is not set and `<Protobuf>` items must be included
481in the project for the `.proto` files to be compiled.
482
483---
484
485## <a name="nocompile"></a>Generate proto and gRPC C# sources from .proto files (no C# compile)
486
487If you just want to generate the C# sources from `.proto` files without compiling the C# files
488 (e.g. for use in other projects) then you can do something similar to this to a `.csproj` file:
489 ```xml
490<ItemGroup>
491  <Protobuf Include="**/*.proto"
492      OutputDir="%(RelativeDir)" CompileOutputs="false"  />
493</ItemGroup>
494```
495
496* `Include` tells the build system to recursively examine project directory and its
497subdirectories (**) include all files matching the wildcard `*.proto`.
498* `OutputDir="%(RelativeDir)"` makes the output directory for each `.cs` file to be
499same as the corresponding `.proto` directory.
500* `CompileOutputs="false"` prevents compiling the generated files into an assembly.
501
502Note that an empty assembly is still generated which can be ignored.
503
504NOTE: To start with an empty project to add your `.proto` files to you can do the following
505at a command prompt:
506```bash
507dotnet new classlib
508rm *.cs              # remove .cs files - for Windows the command is: del *.cs /y
509dotnet add package Grpc.Tools
510```
511
512---
513## <a name="visualstudio"></a>Visual Studio: setting per-file `.proto` file options
514
515In Visual Studio it is possible to set some frequently used per-file options on `.proto` files
516without editing the `.csproj` file directly. However editing the `.csproj` gives you more
517flexibilty.
518
519### "dotnet SDK" projects
520
521For a "dotnet SDK" project, you have more control of some frequently used options.
522**You may need to open and close Visual Studio** for this form to appear in the
523properties window after adding a reference to `Grpc.Tools` package:
524
525![Properties in an SDK project](doc/integration.md-fig.2-sdk.png)
526
527You can also change options of multiple files at once by selecting them in the
528Project Explorer together.
529
530### "classic" projects
531
532For a "classic" project, you can only add `.proto` files with all options set to
533default. Click on the "show all files" button, add files to project, then
534change file type of the `.proto` files to "Protobuf" in the Properties window
535drop-down. This menu item will appear after you import the `Grpc.Tools` package:
536
537![Properties in a classic project](doc/integration.md-fig.1-classic.png)
538
539---
540## <a name="compiler"></a>Bypassing Grpc.Tools to run the protocol buffers compiler explicitly
541
542It is possible to bypass all the build logic in `Grpc.Tools` and run the protocol buffers compiler
543explicitly in your project file, and just use the `Grpc.Tools` as a means of getting the compiler.
544**This is not recommended** but there may be situations where you want to do this.
545
546You can use the following Properties:
547* `Protobuf_ProtocFullPath` points to the full path and filename of protoc executable, e.g.
548  `"...\.nuget\packages\grpc.tools\2.51.0\build\native\bin\windows\protoc.exe"`
549
550* `gRPC_PluginFullPath` points to the full path and filename of gRPC plugin, e.g.
551  `"...\.nuget\packages\grpc.tools\2.51.0\build\native\bin\windows\grpc_csharp_plugin.exe"`
552
553* `Protobuf_StandardImportsPath` points to the standard proto import directory, e.g.
554  `"...\.nuget\packages\grpc.tools\2.51.0\build\native\include"`. This is
555  the directory where a declaration such as `import "google/protobuf/wrappers.proto";`
556  in a proto file would find its target.
557
558then in your project file:
559
560```xml
561  <Target Name="MyProtoCompile">
562    <PropertyGroup>
563      <ProtoCCommand>$(Protobuf_ProtocFullPath) --plugin=protoc-gen-grpc=$(gRPC_PluginFullPath)  -I $(Protobuf_StandardImportsPath) ....rest of your command.... </ProtoCCommand>
564    </PropertyGroup>
565    <Message Importance="high" Text="$(ProtoCCommand)" />
566    <Exec Command="$(ProtoCCommand)" />
567  </Target>
568```
569Do not include any `<Protobuf>` items in the project file as that will invoke the `Grpc.Tools` build and your files will be compiled twice.
570
571---
572
573## <a name="unsupported-arch"></a>Using Grpc.Tools with unsupported architectures
574
575You may still use the MSBuild integration provided by `Grpc.Tools` for architectures where
576the binaries are not included in the `Grpc.Tools` NuGet package.
577
578If you are able to build your own binaries for `protoc` and `grpc_csharp_plugin`, or
579find pre-built binaries provided by the community, then you can define a couple of
580environment variables to tell `Grpc.Tools` to use those binaries instead of the ones
581provided in the NuGet package:
582* `PROTOBUF_PROTOC`  - Full path to the protocol buffers compiler
583* `GRPC_PROTOC_PLUGIN` - Full path to the `grpc_csharp_plugin`
584
585Things to note:
586*  You need `Grpc.Tools` version 2.50.0 or later for these environment variables to
587be recognised.
588
589* The binaries bundled in `Grpc.Tools` already ensure that the correct and mutually
590compatible version of `protoc` and `grpc_csharp_plugin` will be chosen, but when
591providing them yourself, you're in charge.
592
593* If the versions of `protoc` and `grpc_csharp_plugin` you provide are mutually
594incompatible then code generated may not work with your application (e.g. breaks
595the build).
596
597* Specifically, older version of plugins may generate incompatible code
598or may not contain patches/fixes.
599
600_An example for Alpine Linux_
601
602For Alpine Linux (which uses the *musl* C standard library) there are community
603provided packages for the protocol buffers compiler and gRPC plugins:
604[https://pkgs.alpinelinux.org/packages?name=grpc-plugins](https://pkgs.alpinelinux.org/packages?name=grpc-plugins)
605
606To use these:
607```bash
608# Build or install the binaries for your architecture.
609
610# e.g. for Alpine Linux the grpc-plugins package can be used
611#  See https://pkgs.alpinelinux.org/package/edge/community/x86_64/grpc-plugins
612apk add grpc-plugins  # Alpine Linux specific package installer
613
614# Set environment variables for the built/installed protoc
615# and grpc_csharp_plugin binaries
616export PROTOBUF_PROTOC=/usr/bin/protoc
617export GRPC_PROTOC_PLUGIN=/usr/bin/grpc_csharp_plugin
618
619# When the dotnet build runs the Grpc.Tools NuGet package will
620# use the binaries pointed to by the environment variables
621dotnet build
622```
623
624---
625
626## <a name="proto-only-nuget"></a>Including `.proto` files in NuGet packages
627
628There might be occassions when you are given a NuGet package that contains
629`.proto` files that you wish to use in your own project, or you may wish to
630package your own `.proto` files in a NuGet package for others to use.
631
632There is no automatic way for `Grpc.Tools` to locate and include `.proto`
633files from other NuGet packages. Below is a suggested convention to use
634when creating NuGet packages that contain `.proto` files.
635
636__Note:__ This is not the same as a NuGet package providing a library built from
637the code generated from the `.proto` files. Below just describes how to provide
638the uncompiled `.proto` files in a NuGet package and have `Grpc.Tools` automatically
639use them.
640
641### Creating the NuGet package
642
643The NuGet package should:
644- provide the `.proto` files in a `content\protos` subdirectory in the package
645- provide a `packagename.targets` file in the `build` subdirectory in the package that:
646  - defines an MSBuild property giving the path to the `.proto` files in the
647    installed package
648  - conditionally updates the `Protobuf_StandardImportsPath` property with the
649    above path so that the files can be found by the protocol buffers compiler
650    - it should be made optional forcing users to *opt in* to including
651      the `.proto` files
652
653For example, for the package `My.Example.Protos`:
654
655My.Example.Protos.nuspec:
656```xml
657<?xml version="1.0"?>
658<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
659  <metadata>
660    <id>My.Example.Protos</id>
661    <version>1.0.0</version>
662    <title>Example package containing proto files</title>
663    <authors>author</authors>
664    <owners>owner</owners>
665    <licenseUrl>license url</licenseUrl>
666    <projectUrl>project url</projectUrl>
667    <description>See project site for more info.</description>
668    <summary>Example package containing proto files.</summary>
669    <releaseNotes>Example package containing proto files</releaseNotes>
670    <copyright>Copyright 2023, My Company.</copyright>
671  </metadata>
672
673  <files>
674    <!-- copy the My.Example.Protos.targets file for MSBuild integration -->
675    <file src="build\**" target="build" />
676    <!-- copy the .proto files into the package -->
677    <file src="proto\**" target="content\protos" />
678  </files>
679</package>
680```
681
682My.Example.Protos.targets:
683```xml
684<?xml version="1.0"?>
685<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
686  <!-- This targets file allows .proto files bundled in package,
687  to be included in Grpc.Tools compilation. -->
688
689  <PropertyGroup>
690    <!-- Define a property containing the path of the proto files.
691         Content from the nupkg. -->
692    <MyExampleProtos_ProtosPath>$( [System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)../content/protos) )</MyExampleProtos_ProtosPath>
693  </PropertyGroup>
694
695  <!-- Run immediately before the Protobuf_BeforeCompile extension point. -->
696  <!-- Only include protos if project has set <IncludeMyExampleProtosProtos>
697       property to true. -->
698  <Target Name="MyExampleProtos_BeforeCompile"
699          BeforeTargets="Protobuf_BeforeCompile"
700          Condition=" '$(IncludeMyExampleProtosProtos)' == 'true' ">
701    <PropertyGroup>
702      <!-- Add proto files by including path in Protobuf_StandardImportsPath.
703           This path is passed to protoc via the -I option -->
704      <Protobuf_StandardImportsPath>$(Protobuf_StandardImportsPath);$(MyPackage_ProtosPath)</Protobuf_StandardImportsPath>
705    </PropertyGroup>
706
707    <!-- These message are not required but included here for diagnostics -->
708    <Message Text="Included proto files at $(MyExampleProtos_ProtosPath) in import path." Importance="high" />
709    <Message Text="Updated proto imports path: $(Protobuf_StandardImportsPath)" Importance="high" />
710  </Target>
711</Project>
712```
713
714### Using the NuGet package
715
716The project needs to add the package containing the `.proto` files:
717```xml
718<PackageReference Include="My.Example.Protos" Version="1.0.0" />
719```
720
721If the project only wants to compile the `.proto` files included in the package
722then all it needs to do is add the `<Protobuf>` items using the property defined
723in the package for the path to the files. For example, if the NuGet package contained
724the file `greet.proto`, then the project should add:
725
726```xml
727<Protobuf Include="$(MyExampleProtos_ProtosPath)/greet.proto" />
728```
729
730However if the provided `.proto` files are to be *imported* by the projects own `.proto`
731files then the `Protobuf_StandardImportsPath` needs updated to add the directory
732containing the package's files.  This is done by setting to `true` the property
733used in the package. For example, if the project has the local `.proto` file
734`my_services.proto` and it imported a file from the package `common_message.proto`,
735then:
736
737```xml
738<PropertyGroup>
739  <!-- Update the Protobuf_StandardImportsPath -->
740  <IncludeMyExampleProtosProtos>true</IncludeMyExampleProtosProtos>
741</PropertyGroup>
742
743<ItemGroup>
744  <!-- my_services.proto imports common_message.proto from the package
745   My.Example.Protos -->
746  <Protobuf Include="my_services.proto" />
747</ItemGroup>
748```
749
750---
751
752## See also
753
754gRPC project documentation:
755* [gRPC for .NET](https://github.com/grpc/grpc-dotnet)
756* [gRPC C# (legacy implementation using gRPC Core library)](https://github.com/grpc/grpc/blob/master/src/csharp/README.md)
757* [Grpc.Tools internals](Grpc.Tools/implementation_notes.md) - implementation notes for how `Grpc.Tools` works
758
759Microsoft documentation:
760* [Microsoft: Overview for gRPC on .NET](https://learn.microsoft.com/en-us/aspnet/core/grpc/)
761* [Microsoft: C# Tooling support for .proto files](https://learn.microsoft.com/en-us/aspnet/core/grpc/basics#c-tooling-support-for-proto-files)
762