I recently worked on a task to deliver protobuf messages through Keryx. I needed to cache these messages in memory and on disk and discovered that the messages were uncompressed. I was glad to find that the protobuf C++ API provides zlib-based compression, since this is a good enough way to quickly reduce storage size and delivery time.
Protobuf provides the GzipOutputStream and GzipInputStream classes in the google::protobuf::io namespace. These classes are defined in google/protobuf/io/gzip_stream.h. However, a few linker errors revealed zlib support was not enabled in my initial protobuf build.
Windows is the main development environment and target for Keryx, so this guide will explain how to enable zlib compression for protobuf 3.5.1 built from source using Visual Studio 2015. The process for building with Visual Studio 2017 should be similar. A simpler approach is to install protobuf with zlib support using vcpkg:
1 |
vcpkg install protobuf[zlib] protobuf[zlib]:x64-windows |
You can learn more about vcpkg at GitHub. This guide will instead explain how to manually clone and build protobuf source from GitHub. The following steps differ slightly from those provided by protobuf developers, but you will still need:
- Git to clone the protobuf and zlib repositories
- CMake and Visual Studio to build protobuf and zlib
Clone and build zlib
The build instructions for protobuf 3.5.1 at GitHub recommend using zlib 1.2.8. Open a command prompt in a workspace folder (e.g., C:\workspace).
Obtain the zlib 1.2.8 source by cloning the v1.2.8 tag from the zlib project at GitHub with the following command:
1 |
git clone -b v1.2.8 https://github.com/madler/zlib.git |
We can reduce the number of commits by cloning just the commits leading to the v1.2.8 tag by using the –single-branch argument:
1 |
git clone -b v1.2.8 --single-branch https://github.com/madler/zlib.git |
and even further by omitting all commit history and cloning only the commit at the v1.2.8 tag with the –depth=1 argument:
1 |
git clone -b v1.2.8 --single-branch --depth=1 https://github.com/madler/zlib.git |
The zlib repository will be inside the zlib directory. Now let’s generate a Visual Studio solution with cmake in a new build directory that installs the resulting files to an install directory:
1 |
cd zlib |
1 |
mkdir build |
1 |
cd build |
1 |
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_INSTALL_PREFIX=../install .. |
We can build the solution by manually opening zlib\build\zlib.sln with Visual Studio, or instead simply build from the command prompt using cmake. The following commands build the ALL_BUILD Visual Studio project in Release and Debug modes:
1 |
cmake --build . --target ALL_BUILD --config Release |
1 |
cmake --build . --target ALL_BUILD --config Debug |
Build the INSTALL Visual Studio project in Release and Debug modes to copy the headers, configuration files, and generated binaries to the installation directory:
1 |
cmake --build . --target INSTALL --config Release |
1 |
cmake --build . --target INSTALL --config Debug |
The cmake-generated zlib INSTALL project does not install the .pdb file generated in Debug mode, so you may want to copy it manually just in case you need to debug into zlib code:
1 |
copy Debug\zlibd.pdb ..\install\bin |
Clone and build protobuf
Change the command prompt directory back to the parent workspace and clone protobuf 3.5.1 from GitHub:
1 |
cd ..\.. |
1 |
git clone -b v3.5.1 --single-branch https://github.com/protocolbuffers/protobuf.git |
Create a directory inside the protobuf clone to hold your cmake-generated Visual Studio solution, e.g., builds (there is already a Bazel configuration file called BUILD at the root of the protobuf repository):
1 |
cd protobuf |
1 |
mkdir builds |
1 |
cd builds |
Go into the new directory and run cmake against the protobuf repository’s cmake directory with the following configuration flags:
- protobuf_BUILD_SHARED_LIBS=ON to enable building shared libraries, i.e., dynamic link library (DLL) files in Windows
- protobuf_BUILD_TESTS=OFF to disable protobuf unit tests and thus avoid introducing a gmock dependency
- protobuf_WITH_ZLIB=ON to enable the use of zlib in protobuf
- protobuf_DEBUG_POSTFIX=d to append the letter d to the base name of debug binary files generated by the build
- protobuf_VERBOSE=ON to enable detailed build logs
- protobuf_MSVC_STATIC_RUNTIME=OFF to use the dynamic runtime instead of a static runtime
- CMAKE_DEBUG_POSTFIX=d to append the letter d to the base name of debug binary files generated by the build, may be redundant or otherwise duplicate protobuf_DEBUG_POSTFIX
- CMAKE_INSTALL_PREFIX=../install to copy headers, configuration files, and generated binaries to an install directory when building the INSTALL project
- ZLIB_ROOT=../../zlib/install to hint to the
FindZLIB cmake module where to search for zlib (the instructions provided in cmake/README.md seemed more cumbersome and did not work for me)
1 2 3 4 5 6 7 8 9 10 11 |
cmake -G "Visual Studio 14 2015 Win64" ^ -Dprotobuf_BUILD_SHARED_LIBS=ON ^ -Dprotobuf_BUILD_TESTS=OFF ^ -Dprotobuf_WITH_ZLIB=ON ^ -Dprotobuf_DEBUG_POSTFIX=d ^ -Dprotobuf_VERBOSE=ON ^ -Dprotobuf_MSVC_STATIC_RUNTIME=OFF ^ -DCMAKE_DEBUG_POSTFIX=d ^ -DCMAKE_INSTALL_PREFIX=../install ^ -DZLIB_ROOT=../../zlib/install ^ ../cmake |
We can then build and install the protobuf Visual Studio solution using cmake, just as we did for zlib:
1 |
cmake --build . --target ALL_BUILD --config Release |
1 |
cmake --build . --target ALL_BUILD --config Debug |
1 |
cmake --build . --target INSTALL --config Release |
1 |
cmake --build . --target INSTALL --config Debug |
The .pdb files generated by the Debug build are not installed by the INSTALL project, but you can copy them manually to the install\bin directory:
1 |
copy Debug\*d.pdb ..\install\bin |
I will explain in an upcoming post how to serialize and unserialize a protobuf message with zlib-backed streams in C++ , as well as unserialize a protobuf message from a byte array of zlib-compressed data with the official protobuf C# API.
This work by Simverge Software LLC is licensed under a Creative Commons Attribution 4.0 International License.