Protocol Buffers Data Type Go Code Generation: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
Line 83: Line 83:


<font size=-2>
<font size=-2>
  ...
  .
├── go.mod
├── pkg
│   ├── main
│   │    └── main.go
│   ├── somepkgpb
│   │    ├── file1.pb.go
│   │    └── file2.pb.go
│   └── someotherpkgpb
│        ├── file3.pb.go
│        └── file4.pb.go
└── protobuf
      ├── somepkgpb
      │    ├── file1.proto
      │    └── file2.proto
      └── someotherpkgpb    ┌───────────────────────────────────┐
          ├── file3.proto ─┤ option go_package = "./somepkgpb";│
          │                └───────────────────────────────────┘
          └── file4.proto
</font>
</font>
The <code>protoc</code> command is:
<syntaxhighlight lang='bash'>
protoc \
  --proto_path=./protobuf \
  --go_out=./pkg \
  somepkgpb/file1.proto somepkgpb/file2.proto someotherpkgpb/file3.proto someotherpkgpb/file4.proto
</syntaxhighlight>


=<tt>--go_opt</tt>=
=<tt>--go_opt</tt>=

Revision as of 19:19, 7 May 2024

External

https://protobuf.dev/reference/go/go-generated

Internal

Overview

Protocol Buffer files are processed by the Protocol Buffer compiler protoc, which needs the Go plugin protoc-gen-go to generate Go code. The plugin is installed as described in the Installation section below. The protoc command line details are discussed in the Code Generation section.

Installation

The generic compiler must be installed with:

brew install protobuf

To generate Go code, the Go plugin must be installed with:

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest

This will install a protoc-gen-go binary in ${GOBIN}.

Code Generation

The compiler requires a mandatory source directory, specified with --proto_path, where it expects the find the .proto Protocol Buffer files, possibly scattered over a directory sub-hierarchy. The Protocol Buffer files are individually specified on the compiler's command line, and their path must be relative to --proto_path.

The compiler creates a single Go source file for each .proto command line-provided input file. The name of the output file is the name of the corresponding .proto file where the .proto extension is replaced with .pb.go. For example, a person.proto Protocol Buffer file will generate a person.pb.go Go source file.

The compiler must know Go package's import path for every .proto it processes, including those transitively depended upon by the .proto files being processed. There are two ways to specify the Go package import path:

The newly created Go source files will be placed under the root directory specified by --go_out, but where exactly depends on the --go_opt compiler flags, as shown below.

  protoc \
    --proto_path=<protocol-buffer-root-source-directory> \
    --go_out=<protocol-buffer-generated-code-root-directory> \
    [--go_opt=...] \
    .../<protocol-buffer-file-1>.proto .../<protocol-buffer-file-1>.proto ...

For more details on a typical Go project layout, see:

Go Project Layout

Declare Package Input Path inside the .proto Files

The Protocol Buffer compiler must know the path of the directory where to place the generated .pb.go file, relative to the --go_out directory. The recommended way to specify this path is to use the go_package option inside the .proto file. The value of the go_package option is the path of the directory, relative to the --go_out directory, where the generated file will be placed.

syntax = "proto3";

option go_package = "./somepkgpb";

message Something { 
  ...
}

compiled with:

protoc ... --go_out=./pkg somefile.proto

will make the compiler to place the generated somefile.pb.go in ./pkg/somepkgpb. Note that the compiler expects the go_package option value to be a filesystem path, so it expects to see at least one "." or a "/".

The package name for the generated code file will be by default automatically inferred to be the last path fragment of the path specified with go_package option. In the example above, the package name will be somepkgpb. An explicit package name may be specified, by separating the name from the import path by a semicolon ("./somepkgpb;someothername"). However, this usage is discouraged since the package name will be derived by default from the import path in a reasonable manner.

Package names should follow Protocol Buffer package name convention.

Package Naming Convention

The package name for the Go source code files generated from .proto files are conventionally suffixed with "pb": somepkgpb.

The package Specifier

There is no correlation between the Go import path and the package specifier in the .proto file. The latter is only relevant to the protobuf namespace, while the former is only relevant to the Go namespace.

The .proto Import Path

There is no correlation between the Go import path and the .proto import path.

Example

A typical layout that includes Protocol Buffer files that will generate code in different packages:

.
├── go.mod
├── pkg
│   ├── main
│   │    └── main.go
│   ├── somepkgpb
│   │    ├── file1.pb.go
│   │    └── file2.pb.go
│   └── someotherpkgpb
│        ├── file3.pb.go
│        └── file4.pb.go
└── protobuf
     ├── somepkgpb
     │    ├── file1.proto
     │    └── file2.proto
     └── someotherpkgpb    ┌───────────────────────────────────┐ 
          ├── file3.proto ─┤ option go_package = "./somepkgpb";│ 
          │                └───────────────────────────────────┘
          └── file4.proto

The protoc command is:

protoc \
  --proto_path=./protobuf \
  --go_out=./pkg \
  somepkgpb/file1.proto somepkgpb/file2.proto someotherpkgpb/file3.proto someotherpkgpb/file4.proto

--go_opt

paths=import

TODO.

paths=source_relative

TODO.

module=${PREFIX}

TODO.

M${PROTO_FILE}=${GO_IMPORT_PATH}

TODO. Use Declare Package Input Path inside the .proto Files instead.