Include a Git revision in firmware with PlatformIO
Posted on 20 May 2021 in Mechatronics
How to include a Git revision in your firmware at build time with PlatformIO.
Note
This article is a comprehensive write up of two PlatformIO issues the author responded to on GitHub.com in late 2020:
PlatformIO supports the generation of dynamic build flags. This feature allows the creation of build flags by executing a user defined script. The script should output one or more gcc -D options to standard output. For example:
-D SRC_REVISION="b4837070c4b10d37acfbf0283b758d38e739a670"
The -D option allows the defination of a macro. From the gcc(1) man page:
- -D name
- Predefine name as a macro, with definition 1.
- -D name=definition
- The contents of definition are tokenized and processed as if they appeared during translation phase three in a #define directive. In particular, the definition will be truncated by embedded newline characters.
Project structure
This example uses a typical PlatformIO project structure:
. ├── src │ └── main.cpp ├── define-git-revision.py └── platformio.ini
Configuration file
The script to run is defined by the build_flags option in platformio.ini. Scripts are indicated by prepending them with a !.
[platformio] description = Include Git revision in firmware with PlatformIO [env:esp32dev] board = esp32dev framework = arduino monitor_speed = 115200 platform = espressif32 build_flags = !python3 define-git-revision.py
User defined script
The following Python script define-git-revision.py will set two predefined macros:
- SRC_REVISION containing the Git revision, for example 97c333a4b3c732523e09742318d7acc52b33dbcc, and
- SRC_STATE defining the state of the working tree as either clean or dirty.
#!/usr/bin/env python3 """Git revision and working tree state""" import subprocess REVISION = subprocess.check_output(["git", "rev-parse", "HEAD"]).strip() if subprocess.check_output(["git", "diff", "--stat"]).strip() == "": STATE = "clean" else: STATE = "dirty" print("-D SRC_REVISION='\"{}\"'".format(REVISION.decode("UTF-8"))) print("-D SRC_STATE='\"{}\"'".format(STATE))
Main.cpp
The predefined macros may be used in src/main.cpp as follows:
#ifndef UNIT_TEST #include <Arduino.h> #ifndef SRC_REVISION #define SRC_REVISION "(revision not defined)" #endif #ifndef SRC_STATE #define SRC_STATE "(state not defined)" #endif void setup() { Serial.begin(115200); } void loop() { Serial.println(SRC_REVISION); Serial.println(SRC_STATE); Serial.println(); delay(1000); } #endif
Output
Example output on the PlatformIO device monitor:
> Executing task: platformio device monitor < --- Available filters and text transformations: colorize, debug, default, direct, esp32_exception_decoder, hexlify, log2file, nocontrol, printable, send_on_enter, time --- More details at http://bit.ly/pio-monitor-filters --- Miniterm on /dev/ttyUSB0 115200,8,N,1 --- --- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- b4837070c4b10d37acfbf0283b758d38e739a670 dirty b4837070c4b10d37acfbf0283b758d38e739a670 dirty