Installation

Embedded Proto consists of two parts. The first is a plugin for protoc, written in Python, which generates the C++ code for your messages. The second is a small C++ library on which the generated code depends. Both come in one package. As of version 4.0.0 this package is on PyPI, and the protobuf compiler comes along with it. You no longer have to install protoc yourself.

The only requirement is Python 3.11 or newer. There are three ways to install Embedded Proto:

  1. With pip, globally or in a virtual environment.
  2. With uv, which does the same a lot faster.
  3. As a git submodule in your project, the way earlier versions were installed.

Which one you choose is up to you. When your project already has a Python virtual environment, install Embedded Proto in there. When you want to track the version of Embedded Proto together with the version of your project in git, use the submodule.

Install with pip

The simplest way is to install the package in a virtual environment of your project:

python -m venv venv
source venv/bin/activate
pip install EmbeddedProto

On Windows, activate the environment with venv\Scripts\activate instead. When you prefer to have the tools available everywhere, install the package globally:

pip install EmbeddedProto

Either way, you now have two commands available: embeddedproto, which generates the code, and protoc-gen-eams, the plugin itself. Check the installation by asking for the version of the protobuf compiler that came with it:

embeddedproto --version

Install with uv

uv is a replacement for pip and venv. It resolves and installs packages in a fraction of the time. In a virtual environment of your project:

uv venv
uv pip install EmbeddedProto

Run the commands through uv, so you do not have to activate the environment:

uv run embeddedproto --version

To have the commands available everywhere, without a virtual environment, install Embedded Proto as a tool:

uv tool install EmbeddedProto

Use Embedded Proto as a submodule

Before version 4.0.0 this was the only way to install Embedded Proto. It is still supported. The advantage is that git tracks which version of Embedded Proto your project uses, and a colleague cloning your project gets the same version. Add the repository as a submodule and commit it:

cd your_project_dir
git submodule add https://github.com/Embedded-AMS/EmbeddedProto.git
git commit -m "Added Embedded Proto as a submodule."

Next, enter the Embedded Proto folder and run the install script. The script creates a virtual environment in the folder and installs the package in it:

cd EmbeddedProto
python install.py

The environment is created with pip by default. When you have uv installed, the same is done a lot faster:

python install.py --installer uv

You can check out the command line parameters of the install script using the help parameter:

python install.py --help

The commands now live in the virtual environment of the submodule. Run them as EmbeddedProto/venv/bin/embeddedproto on Linux and macOS, or EmbeddedProto\venv\Scripts\embeddedproto on Windows. Two small scripts, protoc-gen-eams and protoc-gen-eams.bat, are included in the root of the submodule. They start the plugin from the virtual environment when you call protoc yourself, as described on the generating source code page.

The C++ source code

The generated code depends on the C++ library of Embedded Proto. When you installed with pip or uv, the source code is inside the package. Ask for its location with:

embeddedproto --cpp-src-location

When you use the submodule, the source code is in the src folder of the submodule. The library is header only, so there is nothing to compile on its own. Add two include paths to your toolchain:

  1. The src folder.
  2. The folder with the generated code.

The headers of the library live in a folder of their own, so that a name like Errors.h cannot collide with a header of your application. Include what you need as <EmbeddedProto/WriteBufferFixedSize.h>, or include the whole library at once with <EmbeddedProto.h>. The generated code includes only what it needs.

Build with C++17. When linking with a C compiler, do not forget to pass -lstdc++ to the linker. This prevents errors like undefined reference to.

A few features of the library are switched on with a compiler define. They are described on their own pages:

DefineEffect
MSG_TO_STRINGEnables the to_string function for debugging.
NULL_TERMINATED_STRINGSReserves one extra character in each string field for a null terminator.
PARTIAL_SERIALIZATION_ENABLEDEnables serializing a message in parts, into a buffer smaller than the message.
EMBEDDED_PROTO_LITTLE_ENDIANSet to 1 or 0 to state the byte order of the target, when the compiler does not. See packed fixed-width fields.

Your license token

With a commercial license you receive a token. The plugin uses it to put your license header on top of each generated file. Set it once, and it is stored in a configuration file in your home folder:

embeddedproto --set-token YOUR_TOKEN

The command directly checks the token with the license server and tells you whether it is active. You can repeat the check at any time with embeddedproto --check-license. When you use the submodule, the install script accepts the same token:

python install.py --token YOUR_TOKEN

The configuration file is ~/.config/embeddedproto/config.ini on Linux and macOS, and %APPDATA%\embeddedproto\config.ini on Windows. Do not commit the token to your repository. On a build server, export it as an environment variable instead. The variable always takes precedence over the configuration file:

export EMBEDDEDPROTO_BUILD_TOKEN=YOUR_TOKEN

For Embedded Proto developers

Embedded Proto uses CMake to build the unit tests. You need CMake 3.28 or newer and a compiler supporting C++17. The unit tests depend on GTest and GMock, which are included as a git submodule. Clone the repository with the recursive option to get them at the same time:

git clone --recursive https://github.com/Embedded-AMS/EmbeddedProto.git
cd EmbeddedProto
python install.py

Next, build and run the unit tests:

scripts/build_test.sh
scripts/run_tests.sh

To run a single test case, call the test executable with a filter:

./build/test/test_EmbeddedProto --gtest_filter="DESIRED_TEST_CASE_NAME"