Skip to content

Commit f25867a

Browse files
gjcairothomasvl
authored andcommitted
Exposes implementationOnlyImports option in SPM plugin
# Conflicts: # Sources/protoc-gen-swift/Docs.docc/index.md
1 parent f4b911d commit f25867a

File tree

3 files changed

+250
-1
lines changed

3 files changed

+250
-1
lines changed

Plugins/SwiftProtobufPlugin/plugin.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ struct SwiftProtobufPlugin: BuildToolPlugin {
6262
var visibility: Visibility?
6363
/// The file naming strategy to use.
6464
var fileNaming: FileNaming?
65+
/// Whether internal imports should be annotated as `@_implementationOnly`.
66+
var implementationOnlyImports: Bool?
6567
}
6668

6769
/// Specify the directory in which to search for
@@ -171,6 +173,10 @@ struct SwiftProtobufPlugin: BuildToolPlugin {
171173
var inputFiles = [Path]()
172174
var outputFiles = [Path]()
173175

176+
if let implementationOnlyImports = invocation.implementationOnlyImports {
177+
protocArgs.append("--swift_opt=ImplementationOnlyImports=\(implementationOnlyImports)")
178+
}
179+
174180
for var file in invocation.protoFiles {
175181
// Append the file to the protoc args so that it is used for generating
176182
protocArgs.append("\(file)")
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
# ``protoc_gen_swift``
2+
3+
@Metadata {
4+
@DisplayName("protoc-gen-swift")
5+
}
6+
7+
Code generation helper for use with Google's `protoc` command.
8+
9+
## Overview
10+
11+
The `protoc-gen-swift` program is a _plugin_ to Google's protoc
12+
compiler that works with protoc to translate proto files into
13+
Swift code.
14+
15+
## Getting Started
16+
17+
If you've worked with Protocol Buffers in other programming
18+
languages before, adding Swift support is
19+
very simple: you just need to build the `protoc-gen-swift` program and
20+
copy it into any directory in your PATH. The protoc program will find
21+
and use it automatically, allowing you to build Swift sources for your
22+
proto files. You will also, of course, need to add the corresponding
23+
Swift runtime library to your project.
24+
25+
### System Requirements
26+
27+
To use Swift with Protocol buffers, you'll need:
28+
29+
* A recent Swift compiler that includes the Swift Package Manager.
30+
We recommend using the latest release build from
31+
[Swift.org](https://swift.org) or the command-line tools included
32+
with the latest version of Xcode.
33+
34+
* Google's protoc compiler. You can get recent versions from
35+
[Google's github repository](https://github.com/protocolbuffers/protobuf).
36+
37+
### Build and Install
38+
39+
Building the plugin should be simple on any supported Swift platform:
40+
41+
```sh
42+
$ git clone https://github.com/apple/swift-protobuf
43+
$ cd swift-protobuf
44+
$ swift build -c release
45+
```
46+
47+
This will create a binary called `protoc-gen-swift` in the
48+
`.build/release` directory. To install, just copy this one executable
49+
anywhere in your PATH.
50+
51+
### Converting .proto files into Swift
52+
53+
To generate Swift output for your .proto files, you run the `protoc`
54+
command as usual, using the `--swift_out=<directory>` option:
55+
56+
```sh
57+
$ protoc --swift_out=. my.proto
58+
```
59+
60+
The `protoc` program will automatically look for `protoc-gen-swift` in your
61+
`PATH` and use it.
62+
63+
Each `.proto` input file will get translated to a corresponding `.pb.swift` file
64+
in the output directory.
65+
66+
#### How to Specify Code-Generation Options
67+
68+
The plugin tries to use reasonable default behaviors for the code it
69+
generates, but there are a few things that can be configured to
70+
specific needs.
71+
72+
You can use the `--swift_opt` argument to `protoc` to pass options to the
73+
Swift code generator as follows:
74+
```sh
75+
$ protoc --swift_opt=[NAME]=[VALUE] --swift_out:. foo/bar/*.proto mumble/*.proto
76+
```
77+
78+
If you need to specify multiple options, you can use more than one
79+
`--swift_opt` argument:
80+
```
81+
$ protoc \
82+
--swift_opt=[NAME1]=[VALUE1] \
83+
--swift_opt=[NAME2]=[VALUE2] \
84+
--swift_out=. foo/bar/*.proto mumble/*.proto
85+
```
86+
87+
_NOTE:_ protoc 3.2.0 does not recognize `--swift_opt` if you rely on
88+
`protoc-gen-swift` being found on the `PATH`. To work around this, you need to
89+
explicitly add the argument `--plugin=[PATH-TO-protoc-gen-swift]` to the
90+
command line, then the `--swift_opt` argument will be understood. If you are
91+
using protoc 3.2.1 or later, then this workaround is _not_ needed.
92+
93+
##### Generation Option: `FileNaming` - Naming of Generated Sources
94+
95+
By default, the paths to the proto files are maintained on the
96+
generated files. So if you pass `foo/bar/my.proto`, you will get
97+
`foo/bar/my.pb.swift` in the output directory. The Swift plugin
98+
supports an option to control the generated file names, the option is
99+
given as part of the `--swift_opt` argument like this:
100+
101+
```
102+
$ protoc --swift_opt=FileNaming=[value] --swift_out=. foo/bar/*.proto mumble/*.proto
103+
```
104+
105+
The possible values for `FileNaming` are:
106+
107+
* `FullPath` (default): Like all other languages, "foo/bar/baz.proto" makes
108+
"foo/bar/baz.pb.swift.
109+
* `PathToUnderscores`: To help with things like the Swift Package
110+
Manager where someone might want all the files in one directory;
111+
"foo/bar/baz.proto" makes "foo_bar_baz.pb.swift".
112+
* `DropPath`: Drop the path from the input and just write all files
113+
into the output directory; "foo/bar/baz.proto" makes "baz.pb.swift".
114+
115+
##### Generation Option: `Visibility` - Visibility of Generated Types
116+
117+
By default, SwiftProtobuf does not specify a visibility for the
118+
generated types, methods, and properties. As a result, these will end
119+
up with the default (`internal`) access. You can change this with the
120+
`Visibility` option:
121+
122+
```
123+
$ protoc --swift_opt=Visibility=[value] --swift_out=. foo/bar/*.proto mumble/*.proto
124+
```
125+
126+
The possible values for `Visibility` are:
127+
128+
* `Internal` (default): No visibility is set for the types, so they get the
129+
default internal visibility.
130+
* `Public`: The visibility on the types is set to `public` so the types will
131+
be exposed outside the module they are compiled into.
132+
133+
134+
##### Generation Option: `ProtoPathModuleMappings` - Swift Module names for proto paths
135+
136+
By default, the code generator assumes all of the resulting Swift files will
137+
be put into the same module. However, since protos can reference types from
138+
another proto file, those generated files might end up in different modules.
139+
This option allows you to specify that the code generated from the proto
140+
files will be distributed in multiple modules. This data is used during
141+
generation to then `import` the module and scope the types. This option
142+
takes the path of a file providing the mapping:
143+
144+
```
145+
$ protoc --swift_opt=ProtoPathModuleMappings=[path.asciipb] --swift_out=. foo/bar/*.proto
146+
```
147+
148+
The format of that mapping file is defined in
149+
[swift_protobuf_module_mappings.proto](../Protos/SwiftProtobufPluginLibrary/swift_protobuf_module_mappings.proto),
150+
and files would look something like:
151+
152+
```
153+
mapping {
154+
module_name: "MyModule"
155+
proto_file_path: "foo/bar.proto"
156+
}
157+
mapping {
158+
module_name: "OtherModule"
159+
proto_file_path: "mumble.proto"
160+
proto_file_path: "other/file.proto"
161+
}
162+
```
163+
164+
The `proto_file_path` values here should match the paths used in the proto file
165+
`import` statements.
166+
167+
168+
##### Generation Option: `ImplementationOnlyImports` - `@_implementationOnly`-annotated imports
169+
170+
By default, the code generator does not annotate any imports with `@_implementationOnly`.
171+
However, in some scenarios, such as when distributing an `XCFramework`, imports
172+
for types used only internally should be annotated as `@_implementationOnly` to
173+
avoid exposing internal symbols to clients.
174+
You can change this with the `ImplementationOnlyImports` option:
175+
176+
```
177+
$ protoc --swift_opt=ImplementationOnlyImports=[value] --swift_out=. foo/bar/*.proto mumble/*.proto
178+
```
179+
180+
The possible values for `ImplementationOnlyImports` are:
181+
182+
* `false` (default): The `@_implementationOnly` annotation will never be used.
183+
* `true`: Imports of internal dependencies and any modules defined in the module
184+
mappings will be annotated as `@_implementationOnly`.
185+
186+
**Important:** Modules cannot be imported as implementation-only if they're
187+
exposed via public API, so even if `ImplementationOnlyImports` is set to `true`,
188+
this will only work if the `Visibility` is set to `internal`.
189+
190+
191+
### Building your project
192+
193+
After copying the `.pb.swift` files into your project, you will need
194+
to add the
195+
[SwiftProtobuf library](https://github.com/apple/swift-protobuf) to
196+
your project to support the generated code. If you are using the
197+
Swift Package Manager, you should first check what version of
198+
`protoc-gen-swift` you are currently using:
199+
200+
```
201+
$ protoc-gen-swift --version
202+
protoc-gen-swift 1.0.1
203+
```
204+
205+
And then add a dependency to your Package.swift file. Adjust the
206+
`Version()` here to match the `protoc-gen-swift` version you checked
207+
above:
208+
209+
```swift
210+
dependencies: [
211+
.package(name: "SwiftProtobuf", url: "https://github.com/apple/swift-protobuf.git", from: "1.6.0"),
212+
]
213+
```
214+
215+
If you are using Xcode, then you should:
216+
217+
* Add the Swift source files generated from your protos directly to your
218+
project.
219+
* Add this SwiftPM package as dependency of your xcode project:
220+
[Apple Docs](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app)
221+
222+
223+
224+
## Internals
225+
226+
When you give `protoc` an option of the form `--XYZ-out`,
227+
it will find and run a program called `protoc-gen-XYZ`.
228+
229+
The `protoc` program then proceeds to read, parse, and validate
230+
all of your proto files.
231+
It feeds this information (as a set of "Descriptor" objects)
232+
to the `protoc-gen-XYZ` program and expects the program to
233+
produce one or more source code files
234+
that `protoc` will then save to the correct output location.
235+
236+
The `protoc-gen-swift` program relies heavily
237+
on the `SwiftProtobuf` library to handle serializing and
238+
deserializing the protobuf-encoded data used to
239+
communicate with `protoc`.
240+
It also relies on another library called `SwiftProtobufPluginLibrary`
241+
that incorporates a lot of the key knowledge about how
242+
to produce Swift source code.

Sources/protoc-gen-swift/Docs.docc/spm-plugin.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ to the root of your target's source folder. An example configuration file looks
6969
"protoFiles": [
7070
"Foo.proto",
7171
],
72-
"visibility": "internal"
72+
"visibility": "internal",
73+
"implementationOnlyImports": true
7374
},
7475
{
7576
"protoFiles": [

0 commit comments

Comments
 (0)