How to set up a project with Embedded Proto using Makefiles

BartExamples, Project Setup

In this example we will demonstrate how to set up a project with Embedded Proto using Makefiles. All the *.proto files will automatically be detected, for each source file code will be generated and build.

The following topics will be addressed:
1. Setup the project
2. Initiating Embedded Proto
3. Including all source files
4. Automatically convert *.proto files
5. Building the project

In this example we will assume you have already installed all the requirements for Embedded Proto. The requirements and installation instructions for your system are described in the Installation section on the documentation page.

Source code
The source code for this example is available on GitHub.

1. Setup the project

In this example we will use the following folder structure:

tree -L 1
├── src
├── proto
├── build
├── embeddedproto
└── Makefile

The src folder contains the source files for this example. The example code on GitHub is based on a NUCLEO-F466RE board made by ST Microelectronics. In the source folder the STM HAL is placed to support the board.

In the proto folder all *.proto files for this example are located. There are two in this case request.proto and reply.proto.

When building all build results will be placed in the build folder.

Just after cloning the example repository you will not yet have the embeddedproto folder. Here we are using Embedded Proto as a git submodule which still needs to be initiated. The following chapter describes how you can do the same for your project.

2. Initiating Embedded Proto

If you are working from the example repository you can check it out and pull the submodule in one command:

git clone --recurse-submodules

If that is the case you can skip the rest and start reading the next section.

Now if you are creating your own project you better make a folder for it. After creating your project folder, change your current directory to the new folder. In that folder we are going to add Embedded Proto as a submodule. After the clone is complete enter the folder and checkout the latest version. To keep track of the version of Embedded Proto you are using in your project, add the .gitmodules file and commit it.

git submodule add
cd embeddedproto
git checkout latest
cd -
git add .gitmodules
git commit –m "Added the Embedded Proto library as a submodule on the latest version."

3. Including all source files

When using wildcards in a makefile the wildcard is executed before build targets. Therefor we can not generate the source files in the first target, add the new files using a wildcard and build the new code in the second target. A solution to this is to add filenames we need by constructing them in the makefile before the actual source code exits.

First lets define some variables we need often.

# Define where the *.proto files are located.
PROTO_DIR = proto

# Define the output directory in which to place the build results.
PROTO_GEN_DIR = build/generated

# The full path location of the Embedded Proto library.
EMBEDDED_PROTO_DIR = $(shell pwd)/embeddedproto

Next we find all the *.proto files in use in the project. For this we do use a wildcard expression.

# Find all the proto files.
# Extend this for subfolders.
PROTO_FILES = $(wildcard $(PROTO_DIR)/*.proto)

Based on the *.proto file names we can change the extension of the files to *.h and store those in a new variable.

# Convert the names of the proto files to the name of the 
# generated header files.

Messages generated by Embedded Proto are pure header files without *.cpp files. The library it self does have a few *.cpp files. Those are the last we need to include.

# These are the source files from the Embedded Proto project.
# These are the files that support your messages.
EMBEDDED_PROTO_SRC := $(wildcard ./embeddedproto/src/*.cpp)

4. Automatically convert *.proto files

So all the *.proto files are located in the proto folder. How do we assure that the makefile finds them and generates code? Again the names of the object files are first generated by means of changing the extension of all *.cpp files.

Next a build target is defined which will generate the header files based on the *.proto files. The build target called generate does not call protoc it self. By adding the list with header filenames as requirements an implicit build target for each header will be called.

# Convert the filenames of source files to object names.

# Major targets
generate: $(PROTO_HDR)
	$(info Done generating source files based on *.proto files.)

# Implicit targets

# This rulle is used to generate the message source files based 
# on the *.proto files.
$(PROTO_GEN_DIR)/%.h: %.proto
	$(shell mkdir -p $(dir $@))
	cd $(EMBEDDED_PROTO_DIR) && $(PROTOC) --plugin=protoc-gen-eams -I../$(PROTO_DIR) --eams_out=../$(PROTO_GEN_DIR) ../$<

The implicit target makes sure the output folder exists and it runs protoc. Protoc is ran from the Embedded Proto folder such that the plugin is found using relative paths. The calls to change the directory and protoc are on one line with ampersands as otherwise each call would be executed in their own shell rendering the change dir useless.

The parameters to protoc make sure the Embedded Proto plugin is used, the required include folder is passed to protoc together with the output folder and last the *.proto file which is being processed is set.

5. Building the project

The final step is to build the project. You can do this simply by adding the generate target as requirement for your debug, release and all targets. This way you can call make generate to just generate the message file or just make to build the whole project without having to call generate separately.

Changes in your proto files will be picked up by the makefile and taken into account in your next build.