xref: /aosp_15_r20/external/grpc-grpc/src/csharp/Grpc.Tools/implementation_notes.md (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1*cc02d7e2SAndroid Build Coastguard Worker# Grpc.Tools MSBuild integration overview
2*cc02d7e2SAndroid Build Coastguard Worker
3*cc02d7e2SAndroid Build Coastguard WorkerThis is an overview for maintainers of Grpc.Tools.
4*cc02d7e2SAndroid Build Coastguard Worker
5*cc02d7e2SAndroid Build Coastguard WorkerThe Grpc.Tools NuGet package provides custom build targets to make it easier to specify `.proto` files
6*cc02d7e2SAndroid Build Coastguard Workerin a project and for those files to be compiled and their generated files to be included in the project.
7*cc02d7e2SAndroid Build Coastguard Worker
8*cc02d7e2SAndroid Build Coastguard Worker# Files in the NuGet package
9*cc02d7e2SAndroid Build Coastguard Worker
10*cc02d7e2SAndroid Build Coastguard Worker## .props and .target files
11*cc02d7e2SAndroid Build Coastguard Worker
12*cc02d7e2SAndroid Build Coastguard WorkerMSBuild properties and targets included from the Grpc.Tools NuGet package are in:
13*cc02d7e2SAndroid Build Coastguard Worker
14*cc02d7e2SAndroid Build Coastguard Worker* `build\Grpc.Tools.props`, which imports
15*cc02d7e2SAndroid Build Coastguard Worker    * `build\_grpc\_Grpc.Tools.props`
16*cc02d7e2SAndroid Build Coastguard Worker    * `build\_protobuf\Google.Protobuf.Tools.props`
17*cc02d7e2SAndroid Build Coastguard Worker* `build\Grpc.Tools.targets`, which imports
18*cc02d7e2SAndroid Build Coastguard Worker    * `build\_grpc\_Grpc.Tools.targets`
19*cc02d7e2SAndroid Build Coastguard Worker    * `build\_protobuf\Google.Protobuf.Tools.targets`
20*cc02d7e2SAndroid Build Coastguard Worker
21*cc02d7e2SAndroid Build Coastguard WorkerDetails of how NuGet packages can add custom build targets and properties to a project is documented
22*cc02d7e2SAndroid Build Coastguard Workerhere: [MSBuild .props and .targets in a package](https://learn.microsoft.com/en-us/nuget/concepts/msbuild-props-and-targets)
23*cc02d7e2SAndroid Build Coastguard Worker
24*cc02d7e2SAndroid Build Coastguard WorkerBasically the `.props` and `.targets` files are automatically included in the projects - the `.props` at the top
25*cc02d7e2SAndroid Build Coastguard Workerof the project and the `.targets` are added to the bottom of the project.
26*cc02d7e2SAndroid Build Coastguard Worker
27*cc02d7e2SAndroid Build Coastguard Worker## Visual Studio property pages
28*cc02d7e2SAndroid Build Coastguard Worker
29*cc02d7e2SAndroid Build Coastguard WorkerFor Visual Studio integration - these files provide the properties pages:
30*cc02d7e2SAndroid Build Coastguard Worker
31*cc02d7e2SAndroid Build Coastguard Worker* `build\_protobuf\Protobuf.CSharp.xml` (included from `Google.Protobuf.Tools.targets`)
32*cc02d7e2SAndroid Build Coastguard Worker* `build\_grpc\Grpc.CSharp.xml` (included from `_Grpc.Tools.targets`)
33*cc02d7e2SAndroid Build Coastguard Worker
34*cc02d7e2SAndroid Build Coastguard Worker## Custom tasks DLLs
35*cc02d7e2SAndroid Build Coastguard Worker
36*cc02d7e2SAndroid Build Coastguard WorkerDLLs containing the custom tasks are in:
37*cc02d7e2SAndroid Build Coastguard Worker
38*cc02d7e2SAndroid Build Coastguard Worker* `build\_protobuf\netstandard1.3`
39*cc02d7e2SAndroid Build Coastguard Worker* `build\_protobuf\net45`
40*cc02d7e2SAndroid Build Coastguard Worker
41*cc02d7e2SAndroid Build Coastguard Worker## Protobuf compiler and C# gRPC plugin binaries
42*cc02d7e2SAndroid Build Coastguard Worker
43*cc02d7e2SAndroid Build Coastguard WorkerNative binary executables for the protobuf compiler (_protoc_) and C# gRPC plugin (_grpc_csharp_plugin_) are
44*cc02d7e2SAndroid Build Coastguard Workerincluded in the NuGet package. Included are binaries for various OSes (Windows, Linux, macOS) and
45*cc02d7e2SAndroid Build Coastguard WorkerCPU architectures (x86, x64, arm64).
46*cc02d7e2SAndroid Build Coastguard Worker
47*cc02d7e2SAndroid Build Coastguard WorkerThe build determines which executables to use for the particular machine that the it is being run on.
48*cc02d7e2SAndroid Build Coastguard WorkerThese can be overridden by specifying MSBuild properties or environment variables to give the paths to custom executables:
49*cc02d7e2SAndroid Build Coastguard Worker
50*cc02d7e2SAndroid Build Coastguard Worker* `Protobuf_ProtocFullPath` property or `PROTOBUF_PROTOC` environment variable \
51*cc02d7e2SAndroid Build Coastguard WorkerFull path of protoc executable
52*cc02d7e2SAndroid Build Coastguard Worker* `gRPC_PluginFullPath` property or `GRPC_PROTOC_PLUGIN` environment variable \
53*cc02d7e2SAndroid Build Coastguard WorkerFull path of gRPC C# plugin
54*cc02d7e2SAndroid Build Coastguard Worker
55*cc02d7e2SAndroid Build Coastguard Worker# Grpc.Tools custom build targets
56*cc02d7e2SAndroid Build Coastguard Worker
57*cc02d7e2SAndroid Build Coastguard Worker## Hooking the custom targets into the project build
58*cc02d7e2SAndroid Build Coastguard Worker
59*cc02d7e2SAndroid Build Coastguard WorkerThe custom targets hook into various places in a normal MSBuild build by specifying
60*cc02d7e2SAndroid Build Coastguard Workerbefore/after targets at the relevant places. See
61*cc02d7e2SAndroid Build Coastguard Worker[msbuild-targets](https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-targets)
62*cc02d7e2SAndroid Build Coastguard Workerfor predefined targets.
63*cc02d7e2SAndroid Build Coastguard Worker
64*cc02d7e2SAndroid Build Coastguard Worker* Before `PrepareForBuild`
65*cc02d7e2SAndroid Build Coastguard Worker    * we add `Protobuf_SanityCheck` that checks this is a supported project type, e.g. a C# project.
66*cc02d7e2SAndroid Build Coastguard Worker* Before `BeforeCompile`
67*cc02d7e2SAndroid Build Coastguard Worker    * we add all the targets that compile the `.proto` files and generate the expected `.cs` files. These files are added to those that get compiled by the C# compiler.
68*cc02d7e2SAndroid Build Coastguard Worker        * The target `_Protobuf_Compile_BeforeCsCompile` is the _glue_ inserting the targets into the build.
69*cc02d7e2SAndroid Build Coastguard Worker        It may look like it isn't doing anything but by specifying `BeforeTargets` and `DependsOnTargets` it inserts `Protobuf_Compile` into the build - but only doing so if this is a C# project.
70*cc02d7e2SAndroid Build Coastguard Worker* After `CoreClean`
71*cc02d7e2SAndroid Build Coastguard Worker    * we add `Protobuf_Clean` that cleans the files generated by the protobuf compiler.
72*cc02d7e2SAndroid Build Coastguard Worker        * The target `_Protobuf_Clean_AfterCsClean` is the _glue_ inserting `Protobuf_Clean` into the build - but only doing so if this is a C# project.
73*cc02d7e2SAndroid Build Coastguard Worker
74*cc02d7e2SAndroid Build Coastguard Worker## Custom tasks
75*cc02d7e2SAndroid Build Coastguard Worker
76*cc02d7e2SAndroid Build Coastguard WorkerThere are a few custom tasks needed by the targets. These are implemented in C# in the Grpc.Tools project
77*cc02d7e2SAndroid Build Coastguard Workerand packaged in the file `Protobuf.MSBuild.dll` in the NuGet package. See [task writing](https://learn.microsoft.com/en-us/visualstudio/msbuild/task-writing) for information about implementing custom tasks.
78*cc02d7e2SAndroid Build Coastguard Worker
79*cc02d7e2SAndroid Build Coastguard Worker* ProtoToolsPlatform
80*cc02d7e2SAndroid Build Coastguard Worker    * Works out the operating system and CPU architecture
81*cc02d7e2SAndroid Build Coastguard Worker* ProtoCompilerOutputs
82*cc02d7e2SAndroid Build Coastguard Worker    * Tries to work out the names and paths of the files that would be generated by the protobuf compiler and returns these as a list of items
83*cc02d7e2SAndroid Build Coastguard Worker    * Also returns list of items that is the same as the `Protobuf` items passed in with the output directory metadata updated
84*cc02d7e2SAndroid Build Coastguard Worker* ProtoReadDependencies
85*cc02d7e2SAndroid Build Coastguard Worker    * Read generated files from previously written dependencies file and return as items.
86*cc02d7e2SAndroid Build Coastguard Worker* ProtoCompile
87*cc02d7e2SAndroid Build Coastguard Worker    * Runs the protobuf compiler for a proto file. The executable to run is specified by the property `Protobuf_ProtocFullPath`
88*cc02d7e2SAndroid Build Coastguard Worker    * To do this it:
89*cc02d7e2SAndroid Build Coastguard Worker        * first writes out a response file containing the parameters for protobuf compiler
90*cc02d7e2SAndroid Build Coastguard Worker        * runs the executable, which generates the `.cs` files and a `.protodep` dependencies file
91*cc02d7e2SAndroid Build Coastguard Worker        * reads the dependencies file to find the files that were generated and these are returned as a list of _items_ that can then be used in the MSBuild targets
92*cc02d7e2SAndroid Build Coastguard Worker
93*cc02d7e2SAndroid Build Coastguard Worker## Build steps
94*cc02d7e2SAndroid Build Coastguard Worker
95*cc02d7e2SAndroid Build Coastguard WorkerThe names of these items and properties are correct at the time of writing this document.
96*cc02d7e2SAndroid Build Coastguard Worker
97*cc02d7e2SAndroid Build Coastguard WorkerHigh level builds steps:
98*cc02d7e2SAndroid Build Coastguard Worker
99*cc02d7e2SAndroid Build Coastguard Worker* Prepare list of `.proto` files to compile
100*cc02d7e2SAndroid Build Coastguard Worker    * Makes sure all needed metadata is set for the `<Protobuf>` item, defaulting some values
101*cc02d7e2SAndroid Build Coastguard Worker    * Removes `<Protobuf>` items that no longer exist or are marked as don't compile
102*cc02d7e2SAndroid Build Coastguard Worker* Handling incremental builds
103*cc02d7e2SAndroid Build Coastguard Worker    * Work out files that need to be created or have changed
104*cc02d7e2SAndroid Build Coastguard Worker* Compile the `.proto` files
105*cc02d7e2SAndroid Build Coastguard Worker* Add generated files to the list of files for the C# compiler
106*cc02d7e2SAndroid Build Coastguard Worker
107*cc02d7e2SAndroid Build Coastguard Worker### Prepare the list of .proto files to compile
108*cc02d7e2SAndroid Build Coastguard Worker
109*cc02d7e2SAndroid Build Coastguard WorkerAt various stages of the build copies of the original `<Protobuf>` items are created
110*cc02d7e2SAndroid Build Coastguard Workerand/or updated to set metadata and to prune out unwanted items.
111*cc02d7e2SAndroid Build Coastguard Worker
112*cc02d7e2SAndroid Build Coastguard WorkerFirstly, the build makes sure `ProtoRoot` metadata is set for all `Protobuf` items.
113*cc02d7e2SAndroid Build Coastguard WorkerA new list of items - `Protobuf_Rooted` - is created from the `Protobuf` items with `ProtoRoot` metadata set:
114*cc02d7e2SAndroid Build Coastguard Worker
115*cc02d7e2SAndroid Build Coastguard Worker* If `ProtoRoot` already set in the `<Protobuf>` item in the project file then it is left as-is.
116*cc02d7e2SAndroid Build Coastguard Worker* If the `.proto` file is under the project's directory then set `ProtoRoot="."`.
117*cc02d7e2SAndroid Build Coastguard Worker* If the `.proto` file is outside of the project's directory then set `ProtoRoot="<relative path to project directory>"`.
118*cc02d7e2SAndroid Build Coastguard Worker
119*cc02d7e2SAndroid Build Coastguard WorkerNow prune out from `Protobuf_Rooted` the items that the user doesn't want to compile - those don't have
120*cc02d7e2SAndroid Build Coastguard Worker`ProtoCompile` metadata as `true`.  The pruned list is now called `Protobuf_Compile`.
121*cc02d7e2SAndroid Build Coastguard Worker
122*cc02d7e2SAndroid Build Coastguard WorkerSet the `Source` metadata on `Protobuf_Compile` items to be the name of the `.proto` file.
123*cc02d7e2SAndroid Build Coastguard WorkerThe `Source` metadata is used later as a key to map generated files to `.proto` files.
124*cc02d7e2SAndroid Build Coastguard Worker
125*cc02d7e2SAndroid Build Coastguard Worker### Handling incremental builds
126*cc02d7e2SAndroid Build Coastguard Worker
127*cc02d7e2SAndroid Build Coastguard Worker#### Gathering files to check for incremental builds
128*cc02d7e2SAndroid Build Coastguard Worker
129*cc02d7e2SAndroid Build Coastguard WorkerThe target `Protobuf_PrepareCompile` tries to work out which files the protobuf compiler will
130*cc02d7e2SAndroid Build Coastguard Workergenerate without actually calling the protobuf compiler. This is a best-effort guess.
131*cc02d7e2SAndroid Build Coastguard WorkerThe custom task `ProtoCompilerOutputs` is called to do this. The results are stored in the
132*cc02d7e2SAndroid Build Coastguard Workeritem list `Protobuf_ExpectedOutputs`.
133*cc02d7e2SAndroid Build Coastguard Worker
134*cc02d7e2SAndroid Build Coastguard WorkerThe target `Protobuf_PrepareCompile` also reads previously written `.protodep` files to get
135*cc02d7e2SAndroid Build Coastguard Workerany actual files previously generated. The custom task `ProtoReadDependencies` is called to
136*cc02d7e2SAndroid Build Coastguard Workerdo this. The results are stored in the item list `Protobuf_Dependencies`.
137*cc02d7e2SAndroid Build Coastguard WorkerThis is in case the list of actual files is different from the previous best-effort guess
138*cc02d7e2SAndroid Build Coastguard Workerfrom `ProtoCompilerOutputs`.
139*cc02d7e2SAndroid Build Coastguard Worker
140*cc02d7e2SAndroid Build Coastguard WorkerThe expected outputs and previous outputs are needed so that the timestamps of those files
141*cc02d7e2SAndroid Build Coastguard Workercan be checked later when handling an incremental build.
142*cc02d7e2SAndroid Build Coastguard Worker
143*cc02d7e2SAndroid Build Coastguard Worker#### Understanding incremental builds
144*cc02d7e2SAndroid Build Coastguard Worker
145*cc02d7e2SAndroid Build Coastguard WorkerTo avoid unnecessarily recompiling the `.proto` files during an incremental build the
146*cc02d7e2SAndroid Build Coastguard Workertarget `_Protobuf_GatherStaleBatched` tries to work out if any files have changed.
147*cc02d7e2SAndroid Build Coastguard Worker
148*cc02d7e2SAndroid Build Coastguard WorkerIt checks for out of date files using MSBuilds incremental build feature that compares the
149*cc02d7e2SAndroid Build Coastguard Workertimestamps on a target's _Input_ files to its _Output_ files.
150*cc02d7e2SAndroid Build Coastguard WorkerSee [How to: Build incrementally](https://learn.microsoft.com/en-us/visualstudio/msbuild/how-to-build-incrementally)
151*cc02d7e2SAndroid Build Coastguard Worker
152*cc02d7e2SAndroid Build Coastguard WorkerThe _Inputs_ that are checked are:
153*cc02d7e2SAndroid Build Coastguard Worker* Timestamps of the `.proto` files
154*cc02d7e2SAndroid Build Coastguard Worker* Timestamps of previously generated files (list of these files read from `.protodep` files)
155*cc02d7e2SAndroid Build Coastguard Worker* Timestamps of MSBuild project files
156*cc02d7e2SAndroid Build Coastguard Worker
157*cc02d7e2SAndroid Build Coastguard WorkerThese are checked against the _Outputs_:
158*cc02d7e2SAndroid Build Coastguard Worker* Timestamps of the expected generated files
159*cc02d7e2SAndroid Build Coastguard Worker
160*cc02d7e2SAndroid Build Coastguard Worker[MSBuild target batching](https://learn.microsoft.com/en-us/visualstudio/msbuild/item-metadata-in-target-batching)
161*cc02d7e2SAndroid Build Coastguard Workeris used to check each `.proto` file against its expected outputs. The batching is done by specifying the `Source`
162*cc02d7e2SAndroid Build Coastguard Workermetadata in the _Input_. Items where `Source` metadata matches in both input and output are in each batch.
163*cc02d7e2SAndroid Build Coastguard Worker
164*cc02d7e2SAndroid Build Coastguard WorkerThe target `_Protobuf_GatherStaleBatched` sets the metadata `_Exec=true` on `_Protobuf_OutOfDateProto`
165*cc02d7e2SAndroid Build Coastguard Workeritems that are out of date.
166*cc02d7e2SAndroid Build Coastguard Worker
167*cc02d7e2SAndroid Build Coastguard WorkerLater in the target `_Protobuf_GatherStaleFiles`, the items in `_Protobuf_OutOfDateProto` that don't have
168*cc02d7e2SAndroid Build Coastguard Workermetadata `_Exec==true` are removed from the list of items, leaving only those that need compiling.
169*cc02d7e2SAndroid Build Coastguard Worker
170*cc02d7e2SAndroid Build Coastguard Worker### Compile the .proto files
171*cc02d7e2SAndroid Build Coastguard Worker
172*cc02d7e2SAndroid Build Coastguard WorkerThe target `_Protobuf_CoreCompile` is run for each `.proto` file that needs compiling.
173*cc02d7e2SAndroid Build Coastguard WorkerThese are in the item list `_Protobuf_OutOfDateProto`. The custom task `ProtoCompile` is called to run the
174*cc02d7e2SAndroid Build Coastguard Workerprotobuf compiler. The files that were generated are returned in the item list `_Protobuf_GeneratedFiles`.
175*cc02d7e2SAndroid Build Coastguard Worker
176*cc02d7e2SAndroid Build Coastguard WorkerIf there are expected files that were not actually generated then the behaviour depends on whether the
177*cc02d7e2SAndroid Build Coastguard Workergenerated files should have been within the project (e.g. in the intermediate directories) or were
178*cc02d7e2SAndroid Build Coastguard Workerspecified to be outside of the project.
179*cc02d7e2SAndroid Build Coastguard Worker* If within the project - empty files are created to prevent incremental builds doing unnecessary recompiles
180*cc02d7e2SAndroid Build Coastguard Worker* If outside the project - by default empty files are not created and a warning is output (this behaviour is configurable)
181*cc02d7e2SAndroid Build Coastguard Worker
182*cc02d7e2SAndroid Build Coastguard Worker**TODO:** why are files inside and outside the project treated differently?
183*cc02d7e2SAndroid Build Coastguard Worker
184*cc02d7e2SAndroid Build Coastguard Worker### Add generated .cs files to the list of files for the C# compiler
185*cc02d7e2SAndroid Build Coastguard Worker
186*cc02d7e2SAndroid Build Coastguard WorkerThe target `_Protobuf_AugmentLanguageCompile` adds to the `Compile` item list
187*cc02d7e2SAndroid Build Coastguard Worker(the list of files that CSC compiles) the expected generated files.
188*cc02d7e2SAndroid Build Coastguard Worker
189*cc02d7e2SAndroid Build Coastguard Worker**Note** - this is the _expected_ files not the _actual_ generated files and this is done
190*cc02d7e2SAndroid Build Coastguard Workerbefore the protobuf compiler is called.
191*cc02d7e2SAndroid Build Coastguard Worker
192*cc02d7e2SAndroid Build Coastguard Worker**TODO:** why are the _expected_ files not the _actual_ generated files added?
193*cc02d7e2SAndroid Build Coastguard Worker
194*cc02d7e2SAndroid Build Coastguard Worker## Handling design time builds
195*cc02d7e2SAndroid Build Coastguard Worker
196*cc02d7e2SAndroid Build Coastguard WorkerDesign-time builds are special builds that Visual Studio uses to gather information about the project.
197*cc02d7e2SAndroid Build Coastguard WorkerThey are not user-initiated but may be triggered whenever files are added, removed or saved.
198*cc02d7e2SAndroid Build Coastguard WorkerSee [Design-Time Builds](https://github.com/dotnet/project-system/blob/main/docs/design-time-builds.md).
199*cc02d7e2SAndroid Build Coastguard Worker
200*cc02d7e2SAndroid Build Coastguard WorkerThe Grpc.Tools build targets used to try and optimise design time builds by disabling calling the
201*cc02d7e2SAndroid Build Coastguard Workerprotobuf compiler during a design time build.  However this optimisation can lead to errors in
202*cc02d7e2SAndroid Build Coastguard WorkerVisual Studio because the generated files may not exist or be out of date and any code that relies
203*cc02d7e2SAndroid Build Coastguard Workeron them will then have errors.
204*cc02d7e2SAndroid Build Coastguard Worker
205*cc02d7e2SAndroid Build Coastguard WorkerNow design time builds behave exactly the same as a normal build.
206*cc02d7e2SAndroid Build Coastguard WorkerThe old behaviour can be enabled by setting the setting `DisableProtobufDesignTimeBuild` property
207*cc02d7e2SAndroid Build Coastguard Workerto `true` in the project file **_if_** it is a design time build, e.g. by adding
208*cc02d7e2SAndroid Build Coastguard Worker
209*cc02d7e2SAndroid Build Coastguard Worker```xml
210*cc02d7e2SAndroid Build Coastguard Worker<PropertyGroup Condition="'$(DesignTimeBuild)' == 'true' ">
211*cc02d7e2SAndroid Build Coastguard Worker    <DisableProtobufDesignTimeBuild>true</DisableProtobufDesignTimeBuild>
212*cc02d7e2SAndroid Build Coastguard Worker</PropertyGroup>
213*cc02d7e2SAndroid Build Coastguard Worker```
214*cc02d7e2SAndroid Build Coastguard Worker
215*cc02d7e2SAndroid Build Coastguard Worker## Automatically including .proto files
216*cc02d7e2SAndroid Build Coastguard Worker
217*cc02d7e2SAndroid Build Coastguard WorkerFor SDK projects it is possible to automatically include `.proto` files found in the project
218*cc02d7e2SAndroid Build Coastguard Workerdirectory or sub-directories, without having to specify them with a `<Protobuf>` item.
219*cc02d7e2SAndroid Build Coastguard WorkerTo do this the property `EnableDefaultProtobufItems` has be set to `true` in the project file.
220*cc02d7e2SAndroid Build Coastguard Worker
221*cc02d7e2SAndroid Build Coastguard WorkerBy default it is not set and `<Protobuf>` items must be included in the project for
222*cc02d7e2SAndroid Build Coastguard Workerthe `.proto` files to be compiled.
223