|
| 1 | +# Generating stubs |
| 2 | + |
| 3 | +Learn how to generate stubs for gRPC Swift from a service defined using the Protocol Buffers IDL. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +If you've used Protocol Buffers before then generating gRPC Swift stubs should be simple. If you're |
| 8 | +unfamiliar with Protocol Buffers then you should get comfortable with the concepts before |
| 9 | +continuing; the [Protocol Buffers website](https://protobuf.dev/) is a great place to start. |
| 10 | + |
| 11 | +You can use the `protoc` plugin from the command line directly, or you can make use of a |
| 12 | + [Swift Package Manager build plugin](https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/Plugins.md) |
| 13 | +convenience which adds the stub generation to the Swift build graph. |
| 14 | +You may use the build plugin either from the command line or from Xcode. |
| 15 | + |
| 16 | +## Using the build plugin |
| 17 | + |
| 18 | +The build plugin (`GRPCProtobufGenerator`) is a great choice for convenient dynamic code generation, however it does come with some limitations. |
| 19 | +Because it generates the gRPC Swift stubs as part of the build it has the requirement that `protoc` must be available |
| 20 | +at compile time. This requirement means it is not a good fit for library authors who do not have |
| 21 | +direct control over this. |
| 22 | + |
| 23 | +The build plugin detects `.proto` files in the source tree and invokes `protoc` once for each file |
| 24 | +(caching results and performing the generation as necessary). |
| 25 | + |
| 26 | +### Adoption |
| 27 | +You must adopt Swift Package Manager build plugins on a per-target basis by modifying your package manifest |
| 28 | +(`Package.swift` file). To do this, declare the grpc-swift-protobuf package as a dependency and add the plugin |
| 29 | +to your desired targets. |
| 30 | + |
| 31 | +For example, to make use of the plugin for generating gRPC Swift stubs as part of the |
| 32 | +`echo-server` target: |
| 33 | +```swift |
| 34 | +targets: [ |
| 35 | + .executableTarget( |
| 36 | + name: "echo-server", |
| 37 | + dependencies: [ |
| 38 | + // ... |
| 39 | + ], |
| 40 | + plugins: [ |
| 41 | + .plugin(name: "GRPCProtobufGenerator", package: "grpc-swift-protobuf") |
| 42 | + ] |
| 43 | + ) |
| 44 | + ] |
| 45 | +``` |
| 46 | +Once this is done you need to ensure that the `.proto` files to be used for generation |
| 47 | +are included in the target's source directory and that you have defined at least one configuration file. |
| 48 | + |
| 49 | +### Configuration |
| 50 | + |
| 51 | +You must provide a configuration file in the directory which encloses all `.proto` files (in the same directory or a parent). |
| 52 | +Configuration files, written in JSON, tell the build plugin about the options used for `protoc` invocations. |
| 53 | +You must name the file `grpc-swift-proto-generator-config.json` and structure it in the following format: |
| 54 | +```json |
| 55 | +{ |
| 56 | + "generate": { |
| 57 | + "clients": true, |
| 58 | + "servers": true, |
| 59 | + "messages": true, |
| 60 | + }, |
| 61 | + "generatedSource": { |
| 62 | + "accessLevelOnImports": false, |
| 63 | + "accessLevel": "internal", |
| 64 | + } |
| 65 | + "protoc": { |
| 66 | + "executablePath": "/opt/homebrew/bin/protoc" |
| 67 | + "importPaths": [ |
| 68 | + "../directory_1", |
| 69 | + ], |
| 70 | + }, |
| 71 | +} |
| 72 | +``` |
| 73 | + |
| 74 | +The options do not need to be specified and each have default values. |
| 75 | + |
| 76 | +| Name | Possible Values | Default | Description | |
| 77 | +|----------------------------------------|--------------------------------------------|--------------|-----------------------------------------------------| |
| 78 | +| `generate.servers` | `true`, `false` | `true` | Generate server stubs | |
| 79 | +| `generate.clients` | `true`, `false` | `true` | Generate client stubs | |
| 80 | +| `generate.messages` | `true`, `false` | `true` | Generate message stubs | |
| 81 | +| `generatedSource.accessLevelOnImports` | `true`, `false` | `false` | Whether imports should have explicit access levels | |
| 82 | +| `generatedSource.accessLevel` | `"public"`, `"package"`, `"internal"` | `"internal"` | Access level for generated stubs | |
| 83 | +| `protoc.executablePath` | N/A | `null`† | Path to the `protoc` executable | |
| 84 | +| `protoc.importPaths` | N/A | `null`‡ | Import paths passed to `protoc` | |
| 85 | + |
| 86 | +† The Swift Package Manager build plugin infrastructure will attempt to discover the executable's location if you don't provide one. |
| 87 | + |
| 88 | +‡ If you don't provide any import paths then the path to the configuration file will be used on a per-source-file basis. |
| 89 | + |
| 90 | +Many of these options map to `protoc-gen-grpc-swift` and `protoc-gen-swift` options. |
| 91 | + |
| 92 | +If you require greater flexibility you may specify more than one configuration file. |
| 93 | +Configuration files apply to all `.proto` files equal to or below it in the file hierarchy. A configuration file |
| 94 | +lower in the file hierarchy supersedes one above it. |
| 95 | + |
| 96 | +### Using protoc |
| 97 | + |
| 98 | +The [`grpc-swift-protobuf`](https://github.com/grpc/grpc-swift-protobuf) package provides |
| 99 | +`protoc-gen-grpc-swift`, a program which is a plugin for the Protocol Buffers compiler, `protoc`. |
| 100 | +To generate gRPC stubs for your `.proto` files directly you must run the `protoc` command with |
| 101 | +the `--grpc-swift_out=<DIRECTORY>` option: |
| 102 | + |
| 103 | +```console |
| 104 | +protoc --grpc-swift_out=. my-service.proto |
| 105 | +``` |
| 106 | + |
| 107 | +> `protoc-gen-grpc-swift` only generates gRPC stubs, it doesn't generate messages. You must use |
| 108 | +> `protoc-gen-swift` to generate messages in addition to gRPC Stubs. |
| 109 | +
|
| 110 | +The presence of `--grpc-swift_out` tells `protoc` to use the `protoc-gen-grpc-swift` plugin. By |
| 111 | +default it'll look for the plugin in your `PATH`. You can also specify the path to the plugin |
| 112 | +explicitly: |
| 113 | + |
| 114 | +```console |
| 115 | +protoc --plugin=/path/to/protoc-gen-grpc-swift --grpc-swift_out=. my-service.proto |
| 116 | +``` |
| 117 | + |
| 118 | +You can also specify various option the `protoc-gen-grpc-swift` via `protoc` using |
| 119 | +the `--grpc-swift_opt` argument: |
| 120 | + |
| 121 | +```console |
| 122 | +protoc --grpc-swift_opt=<OPTION_NAME>=<OPTION_VALUE> --grpc-swift_out=. |
| 123 | +``` |
| 124 | + |
| 125 | +You can specify multiple options by passing the `--grpc-swift_opt` argument multiple times: |
| 126 | + |
| 127 | +```console |
| 128 | +protoc \ |
| 129 | + --grpc-swift_opt=<OPTION_NAME1>=<OPTION_VALUE1> \ |
| 130 | + --grpc-swift_opt=<OPTION_NAME2>=<OPTION_VALUE2> \ |
| 131 | + --grpc-swift_out=. |
| 132 | +``` |
| 133 | + |
| 134 | +#### Generator options |
| 135 | + |
| 136 | +| Name | Possible Values | Default | Description | |
| 137 | +|---------------------------|--------------------------------------------|------------|----------------------------------------------------------| |
| 138 | +| `Visibility` | `Public`, `Package`, `Internal` | `Internal` | Access level for generated stubs | |
| 139 | +| `Server` | `True`, `False` | `True` | Generate server stubs | |
| 140 | +| `Client` | `True`, `False` | `True` | Generate client stubs | |
| 141 | +| `FileNaming` | `FullPath`, `PathToUnderscore`, `DropPath` | `FullPath` | How generated source files should be named. (See below.) | |
| 142 | +| `ProtoPathModuleMappings` | | | Path to module map `.asciipb` file. (See below.) | |
| 143 | +| `UseAccessLevelOnImports` | `True`, `False` | `False` | Whether imports should have explicit access levels. | |
| 144 | + |
| 145 | +The `FileNaming` option has three possible values, for an input of `foo/bar/baz.proto` the following |
| 146 | +output file will be generated: |
| 147 | +- `FullPath`: `foo/bar/baz.grpc.swift`. |
| 148 | +- `PathToUnderscore`: `foo_bar_baz.grpc.swift` |
| 149 | +- `DropPath`: `baz.grpc.swift` |
| 150 | + |
| 151 | +The code generator assumes all inputs are generated into the same module, `ProtoPathModuleMappings` |
| 152 | +allows you to specify a mapping from `.proto` files to the Swift module they are generated in. This |
| 153 | +allows the code generator to add appropriate imports to your generated stubs. This is described in |
| 154 | +more detail in the [SwiftProtobuf documentation](https://github.com/apple/swift-protobuf/blob/main/Documentation/PLUGIN.md). |
| 155 | + |
| 156 | +#### Building the protoc plugin |
| 157 | + |
| 158 | +> The version of `protoc-gen-grpc-swift` you use mustn't be newer than the version of |
| 159 | +> the `grpc-swift-protobuf` you're using. |
| 160 | +
|
| 161 | +If your package depends on `grpc-swift-protobuf` then you can get a copy of `protoc-gen-grpc-swift` |
| 162 | +by building it directly: |
| 163 | + |
| 164 | +```console |
| 165 | +swift build --product protoc-gen-grpc-swift |
| 166 | +``` |
| 167 | + |
| 168 | +This command will build the plugin into `.build/debug` directory. You can get the full path using |
| 169 | +`swift build --show-bin-path`. |
0 commit comments