Tip: Automate Software Versioning with Bash Script

A lot of startups are too busy to create their next hit firmware to bother with organizing a workflow, like an automatic software release version numbering. Petty, because it is so helpful to setup a proper company culture up front and force every programer to modify their development environment to automatically execute a simple script after each compile.

This post only illustrates only one way about it. We elected to name our firmware with three number groups separated with a dot, for example 1.23.150, representing version MAJOR.MINOR.BUILD.

The MAJOR is incremented only when an important change is introduced, when the release brings major change. This is incremented in the firmware by hand by the programmer, the automatic script never modifies its value. This usually happens about once or twice per year. Most products end up having only a single digit value for MAJOR version.

The MINOR is also only modified only by the programmer, but much more often. This is often reaching two digit values. We like to increment it when any issue is solved or small functionality added.

This brings up to the most important part from the development and bug solving point of view, to the BUILD numbering. It is incremented automatically by the script after each compile, thus reaches very quickly a three digit number. It helps very much during the development to track the source code changes. When our beta testers report any bugs, we can easily lookup the date in the git repository, restore and test the same code in our lab.

Important to note, that when MAJOR.MINOR gets incremented, the code should be tested by at least one person to ensure it is a stable release. The same is not true for the BUILD number – many builds are not even functional. For example, it might be that version 1.23.138 is a usable product, then several builds after that are not until 1.23.150. Those builds in-between still exist in the git repository, but will never reach any beta testers.

We always keep the version numbers in its own separate version.h file:

**
 * @file:   version.h
 * @brief Contains the current software version, with the BUILD incremented after each compile.
 *
 * @author: Ivan K
 * @date August 4, 2020
 */

#ifndef VERSION_H
#define	VERSION_H

#define version_major   1
#define version_minor   23
#define version_build   150

#endif	/* !VERSION_H */

This file is read by the script after each compile. The script will simply locate the line with version_build in it, locate the number after the words (in this case 150) and increment it (to 151). We use a bash script, but certainly any other language will do the same:

#!/bin/bash

echo ;
echo "----------------------------------------------------------------";
echo "               Autoincrement version number";
echo "(locates version number in 'version.h' and increments it by one)";
echo "----------------------------------------------------------------";
echo ;

orig_file="version.h";
temp_file="version.tmp";

#create empty output file, will append lines later
echo -n "" > $temp_file;

MAJOR=$(cat $orig_file |grep "version_major"|awk '{print $3}');
MINOR=$(cat $orig_file |grep "version_minor"|awk '{print $3}');

OLD_BUILD=$(cat $orig_file |grep "version_build"|awk '{print $3}');
NEW_BUILD=$((OLD_BUILD+1));

echo "old version number = $MAJOR.$MINOR.$OLD_BUILD";
echo "new version number = $MAJOR.$MINOR.$NEW_BUILD";
echo ;

# copy line by line to temp file, modify only the one line with build number in it
while read LINE;
do
  THIS_ONE=$(echo "$LINE" | grep "version_build" | wc -l);
  if [ $THIS_ONE == 1 ]
    then
      echo "#define version_build   $NEW_BUILD" >> $temp_file;
    else
      echo "$LINE" >> $temp_file;
  fi
done < $orig_file

# replace the original file with the newly created temp file
rm $orig_file;
mv $temp_file $orig_file;

exit 0

Probably every development environment offers a setting, where one can enter project build properties. In MPLAB from Microchips you find it under Project Properties / Conf / Building / Execute this line after build:

Another popular development environment is STM32CubeIDE. Right click on the project in the Project Explorer, go to C/C++ Build / Settings, select the tab Build Steps, and fill out the Post-build steps field.