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