Getting Started with Protocol Buffers

Getting Started with Protocol Buffers

You should use Google's Protocol Buffers to store the messages sent between servers in the Raft projects: they handle a bunch of serialization and deserialization issues that you would otherwise have to address yourself. Here are a few bits and pieces of information to help you get started with protobufs.

  • I recommend that you use proto3 (the newest version of protobufs) since it provides additional facilities for defining messages, such as oneof.

  • The root of the documentation for protobufs is at https://developers.google.com/protocol-buffers.

  • To install protobufs as a Git submodule of your project, cd to the top-level project directory and then invoke the following shell commands:

    mkdir install
    git submodule add https://github.com/protocolbuffers/protobuf.git
    cd protobuf
    git submodule update --init --recursive
    cmake . -DCMAKE_INSTALL_PREFIX=../install -DCMAKE_CXX_STANDARD=17
    cmake --build . --parallel 10
    cmake --install .
    

    This will create a protoc executable in the directory install/bin, which you can use to compile your .proto files as described below. I'd recommend adding the install/bin directory to your PATH environment variable. The commands above will also create numerous library files in the directory install/lib, which you will need to link your applications against (see below).

  • The first step is to learn about the special-purpose language for defining message formats (.proto files). For an introduction to this, see the Language Guide for proto3.

  • Once you've written your .proto files, you'll need to use protoc to compile them into C++ header and class files. To do that, invoke the following shell command:

    protoc -I $SRC_DIR --cpp_out $DST_DIR foo.proto
    

    In this command, foo.proto is the name of the file to compile, $SRC_DIR is the name of the directory containing foo.proto (often .), and $DST_DIR is the name of the directory where protoc should place the .pb.h and .pb.cc files (often . as well). You should set up your Makefile to rerun protoc whenever a .proto file changes.

  • Next, you'll need to learn about instantiating protobuf objects and the methods available for reading and writing fields in them. This is also described in C++ Protocol Buffer Basics.

  • You'll also need to learn how to serialize protobufs (e.g., into strings) for transmitting over the network, and how to deserialize back from network data to protobuf objects. This is done with methods such as SerializeToString and ParseFromString. There are also many other options available, depending on how you want to structure your code. The best way to learn about these methods is with the C++ API documentation. In particular, the serialization and deserialization methods are all part of the MessageLite class, which is a superclass of all the protobuf classes.

  • Finally, you'll need to compile your application files along with the .pb.cc files generated by protoc and many library files from the install/include/lib directory. Compile the .pb.cc files just like your application files, except you'll also need to specify

    -I install/include
    

    on the command line so that the compiler can find protobuf header files (you may also need this option when compiling your application files that use protocol buffers). To link with the appropriate library packages, add the following lines to your Makefile:

    LIBS := $(shell export PKG_CONFIG_PATH=install/lib/pkgconfig; \
          pkg-config --libs protobuf)
    

    Then in the Makefile lines that compile final executables, add $(LIBS).

Installation on MacOS

The instructions above work for Linux, but installing Protocol Buffers under MacOS may require additional work. Here is one set of instructions that seems to work (it ensures that protobufs link against a local installation of Abseil):

  • Before the command sequence above, invoke
    brew install abseil
    brew info abseil
    
  • Save information about Abseil's installation path.
  • In the command sequence above, replace the first cmake command with this:
    export ABSEIL_PATH=<path from brew info abseil above>
    cmake . -DCMAKE_INSTALL_PREFIX=../install -DCMAKE_CXX_STANDARD=17 -Dprotobuf_ABSL_PROVIDER=package -DCMAKE_PREFIX_PATH=$(ABSEIL_PATH)
    

Alternate instructions for installing on MacOS are available in this gist: https://gist.github.com/madelinegannon/393fe7b1a24664abd0976467162f5f14

You may also need to delete existing installations of protobufs:

brew uninstall protobuf

After installation, if you invoke

protoc --version

it should return something like libprotoc 3.x.x. If it returns a version number like libprotoc 25.x.x, you might have an extra protobuf installation hidden in your system that is conflicting with the one you want.