Skip to content

Add more documentation about code generation #83

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Code generation with protoc

This article describes how to use the Swift Package Manager build plugin to
generate gRPC Swift and Swift Protobuf code from your Protocol Buffers `.proto` files.

## Overview

If you've used Protocol Buffers before then generating gRPC Swift stubs should be simple. If you're
unfamiliar with Protocol Buffers then you should get comfortable with the concepts before
continuing; the [Protocol Buffers website](https://protobuf.dev/) is a great place to start.

If you haven't installed `protoc` yet refer to <doc:Installing-protoc> for
instructions.

## Using protoc

The [`grpc-swift-protobuf`](https://github.com/grpc/grpc-swift-protobuf) package provides
`protoc-gen-grpc-swift-2`, a program which is a plugin for the Protocol Buffers compiler, `protoc`.
To generate gRPC stubs for your `.proto` files directly you must run the `protoc` command with
the `--grpc-swift-2_out=<DIRECTORY>` option:

```console
protoc --grpc-swift-2_out=. my-service.proto
```

> `protoc-gen-grpc-swift-2` only generates gRPC stubs, it doesn't generate messages. You must use
> `protoc-gen-swift` to generate messages in addition to gRPC Stubs.
Comment on lines +26 to +27
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm unsure about this, but should we maybe put this at the top of this section and slightly rephrase it to something like "you should first make sure you've generated your proto messages by using protoc-gen-swift before generating gRPC Stubs?

I just feel like if you're completely new to all of this, this paragraph may be confusing?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't matter which order they're generated in, it can be before or after generating gRPC stubs. I think this is in the right place because the paragraph above sets the scene by explaining that we provide a plugin for protoc which generates the gRPC bits. This is just making it more explicit that it only generates the gRPC bits.


The presence of `--grpc-swift-2_out` tells `protoc` to use the `protoc-gen-grpc-swift-2` plugin. By
default it'll look for the plugin in your `PATH`. You can also specify the path to the plugin
explicitly:

```console
protoc --plugin=/path/to/protoc-gen-grpc-swift-2 --grpc-swift-2_out=. my-service.proto
```

You can specify various options to `protoc-gen-grpc-swift-2` via `protoc` using
the `--grpc-swift-2_opt` argument:

```console
protoc --grpc-swift-2_opt=<OPTION_NAME>=<OPTION_VALUE> --grpc-swift-2_out=.
```

You can specify multiple options by repeating the `--grpc-swift-2_opt` argument:

```console
protoc \
--grpc-swift-2_opt=<OPTION_NAME1>=<OPTION_VALUE1> \
--grpc-swift-2_opt=<OPTION_NAME2>=<OPTION_VALUE2> \
--grpc-swift-2_out=.
```

### Generator options

| Name | Possible Values | Default | Description |
|---------------------------|---------------------------------------------|-----------------|----------------------------------------------------------|
| `Visibility` | `Public`, `Package`, `Internal` | `Internal` | Access level for generated stubs |
| `Server` | `True`, `False` | `True` | Generate server stubs |
| `Client` | `True`, `False` | `True` | Generate client stubs |
| `FileNaming` | `FullPath`, `PathToUnderscores`, `DropPath` | `FullPath` | How generated source files should be named. † |
| `ProtoPathModuleMappings` | | | Path to module map `.asciipb` file. ‡ |
| `UseAccessLevelOnImports` | `True`, `False` | `False` | Whether imports should have explicit access levels. |
| `GRPCModuleName` | | `GRPCCore` | The name of the `GRPCCore` module. |
| `GRPCProtobufModuleName` | | `GRPCProtobuf` | The name of the `GRPCProtobuf` module. |
| `SwiftProtobufModuleName` | | `SwiftProtobuf` | The name of the `SwiftProtobuf` module. |
| `Availability` | String, in the form `OS Version` | | Platform availability to use in generated code. § |

† The `FileNaming` option has three possible values, for an input of `foo/bar/baz.proto` the following
output file will be generated:
- `FullPath`: `foo/bar/baz.grpc.swift`.
- `PathToUnderscores`: `foo_bar_baz.grpc.swift`
- `DropPath`: `baz.grpc.swift`

‡ The code generator assumes all inputs are generated into the same module, `ProtoPathModuleMappings`
allows you to specify a mapping from `.proto` files to the Swift module they are generated in. This
allows the code generator to add appropriate imports to your generated stubs. This is described in
more detail in the [SwiftProtobuf documentation](https://github.com/apple/swift-protobuf/blob/main/Documentation/PLUGIN.md).

§ If unspecified the following availability is used: macOS 15, iOS 18, tvOS 18,
watchOS 11, visionOS 2. The `Availability` option may be specified multiple
times, where each value is a space delimited pair of platform and version, e.g.
`Availability=macOS 15.0`.

### Building the protoc plugin

> The version of `protoc-gen-grpc-swift-2` you use mustn't be newer than the version of
> the `grpc-swift-protobuf` you're using.

If your package depends on `grpc-swift-protobuf` then you can get a copy of `protoc-gen-grpc-swift-2`
by building it directly:

```console
swift build --product protoc-gen-grpc-swift-2
```

This command will build the plugin into `.build/debug` directory. You can get the full path using
`swift build --show-bin-path`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Code generation with the build plugin

This article describes how to use `protoc` to generate stubs for gRPC Swift and
Swift Protobuf from your Protocol Buffers `.proto` files.

## Overview

The build plugin (`GRPCProtobufGenerator`) is a great choice for convenient
dynamic code generation, however it does come with some limitations. Because it
generates the gRPC Swift stubs as part of the build it has the requirement that
`protoc` must be available at compile time. This requirement means it is not a
good fit for library authors who do not have direct control over this.

To learn more about other options for code generation see <doc:Generating-stubs>.

The build plugin works by detecting `.proto` files in the source tree and
invokes `protoc` once for each file (caching results and performing the
generation as necessary).

If you haven't installed `protoc` yet refer to <doc:Installing-protoc> for
instructions.

### Adoption

You must adopt Swift Package Manager build plugins on a per-target basis by
modifying your package manifest (`Package.swift` file). To do this, declare the
`grpc-swift-protobuf` package as a dependency and add the plugin to your desired
targets.

For example, to make use of the plugin for generating gRPC Swift stubs as part
of the `echo-server` target:

```swift
targets: [
.executableTarget(
name: "echo-server",
dependencies: [
// ...
],
plugins: [
.plugin(
name: "GRPCProtobufGenerator",
package: "grpc-swift-protobuf"
)
]
)
]
```

Once this is done you need to ensure that the `.proto` files to be used for
generation are included in the target's source directory and that you have
defined a configuration file.

## Configuration

You must provide a configuration file named
`grpc-swift-proto-generator-config.json` in the directory which encloses all
`.proto` files (in the same directory as the files or a parent directory). The
configuration file tells the build plugin about the options used for `protoc`
invocations.

> Warning:
> The name of the config file is important and must match exactly, the
> plugin won't be applied if it can't find the config file.

You can use the following as a starting point for your configuration:

```json
{
"generate": {
"clients": true,
"servers": true,
"messages": true
}
}
```

By default clients, servers, and messages will be generated with the `internal`
access level.

The full structure of the config file looks like this:

```json
{
"generate": {
"clients": true,
"servers": true,
"messages": true
},
"generatedSource": {
"accessLevelOnImports": false,
"accessLevel": "internal"
},
"protoc": {
"executablePath": "/opt/homebrew/bin/protoc",
"importPaths": [
"../directory_1"
]
}
}
```

Each of the options are described below:

| Name | Possible Values | Default | Description |
|----------------------------------------|--------------------------------------------|--------------|-----------------------------------------------------|
| `generate.servers` | `true`, `false` | `true` | Generate server stubs |
| `generate.clients` | `true`, `false` | `true` | Generate client stubs |
| `generate.messages` | `true`, `false` | `true` | Generate message stubs |
| `generatedSource.accessLevelOnImports` | `true`, `false` | `false` | Whether imports should have explicit access levels |
| `generatedSource.accessLevel` | `"public"`, `"package"`, `"internal"` | `"internal"` | Access level for generated stubs |
| `protoc.executablePath` | N/A | `null`† | Path to the `protoc` executable |
| `protoc.importPaths` | N/A | `null`‡ | Import paths passed to `protoc` |

† The Swift Package Manager build plugin infrastructure will attempt to discover
the executable's location if you don't provide one.

‡ If you don't provide any import paths then the path to the configuration file
will be used on a per-source-file basis.

Many of these options map to `protoc-gen-grpc-swift-2` and `protoc-gen-swift`
options.

If you require greater flexibility you may specify more than one configuration
file. Configuration files apply to all `.proto` files equal to or below it in
the file hierarchy. A configuration file lower in the file hierarchy supersedes
one above it.
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Code generation with generate-grpc-code-from-protos

This article describes how to use the `generate-grpc-code-from-protos` Swift
Package Manager command plugin to generate gRPC Swift and Swift Protobuf code
from your Protocol Buffers `.proto` files.

This plugin is particularly useful for:

- **Manual, on-demand code generation:** When you prefer to explicitly generate
code rather than relying on a build tool plugin.
- **Libraries:** For Swift packages intended as libraries, where generated
source code should be checked into your repository to avoid external `protoc`
dependencies for your library's consumers.

If you haven't installed `protoc` yet refer to <doc:Installing-protoc> for
instructions.

## Adding the Plugin to Your Package

To use `generate-grpc-code-from-protos` your package needs to depend on
`grpc-swift-protobuf`. You **don't** need to add a dependency on each target
like you would for the build plugin.

## Basic Usage

Once your package depends on `grpc-swift-protobuf` you can invoke it using:

```sh
swift package generate-grpc-code-from-protos path/to/YourService.proto path/to/YourMessages.proto
```

If you've organised your protos within a single directory then you can
pass the path of the directory as an argument instead, the plugin will find
all `.proto` files nested within that directory:

```sh
swift package generate-grpc-code-from-protos Protos
```

By default the plugin generates code for gRPC servers, clients, and Protobuf
messages into the current working directory. To change where the code is
generated you can specify the `--output-path` option:


```sh
swift package generate-grpc-code-from-protos --output-path Sources/Generated -- Protos
```

> Important: The "`--`" separates options and inputs passed to the plugin.
>
> Everything after "`--`" is treated as an input (a `.proto` file or a
> directory), everything before "`--`" is treated as an option with a value or
> a flag. If there is no "`--`" then all arguments are treated as input.

You should now have a basic understanding of how to use the plugin. You can
configure how the code is generated via a number of options, a few commonly used
ones are:
- `--no-client` disables client code generation,
- `--no-server` disables server code generation,
- `--no-messages` disables message code generation,
- `--access-level <access>` specifies the access level of the generated code,
(`<access>` must be one of "internal", "package", or "public").

You can read about other options by referring to the `--help` text:

```sh
swift package generate-grpc-code-from-protos --help
```

### Permissions

Swift Package Manager command plugins require permission to create files. You'll
be prompted to give `generate-grpc-code-from-protos` permission when running it.
To avoid being prompted you can grant permissions ahead of time by specifying
`--allow-writing-to-package-directory` to the `swift package` command. For
example:

```sh
swift package --allow-writing-to-package-directory generate-grpc-code-from-protos Protos
```
Loading