Wednesday, December 17, 2008

Automatic build number generation

Version tracking is essential for several reasons. Without a proper versioning system it's difficult to know if this or that firmware contains certain update or feature, specially if one forgets to increment the version number.

That's where the build number appears, assigning a unique number per build (or 'make' in this special case). That way it can't go wrong. Version number is still there but there is also a build number, uniquely defining the release.

I usually never reset the build number, so even if the version number jumps (modified manually) the build number will always increment. It's not mandatory, it depends on how you feel about it.


Here is an automatic build number generator. It's a shell script based on sh. I used it with Windows without any problems as long as sh and friends are available on the system path.

version="`sed 's/^ *//' major_version`"
old="`sed 's/^ *//' build.number` +1"
echo $old | bc > build.number.temp
mv build.number.temp build.number
echo "$version`sed 's/^ *//' build.number` - `date`" > version.number
echo "#ifndef BUILD_NUMBER_STR" > build_number.h
echo "#define BUILD_NUMBER_STR \"`sed 's/^ *//' build.number`\"" >> build_number.h
echo "#endif" >> build_number.h

echo "#ifndef VERSION_STR" >> build_number.h
echo "#define VERSION_STR \"$version`sed 's/^ *//' build.number` - `date`\"" >> build_number.h
echo "#endif" >> build_number.h

echo "#ifndef VERSION_STR_SHORT" >> build_number.h
echo "#define VERSION_STR_SHORT \"$version`sed 's/^ *//' build.number`\"" >> build_number.h
echo "#endif" >> build_number.h

In order to make it work a file named major_version has to be created. It should contain something like "1.02." (no double commas). A file called build.number is also needed. It will be the starting build number like "1". Version number won't be modified but build number will be incremented each time is executed. In order to be useful for C programming the header file build_number.h is updated to reflect both build.number and major_version.

I usually create a makefile dependency to perform automatic build number generation by adding something like this to the Makefile:

# main rule
all: build_number.h $(TARGET).whatever $(TARGET).other
@whatever rules

# rule for build number generation
build_number.h: $(SOURCES)
@echo Generating build number..

A new build number is assigned every time a source file is modified. There can be other approachs too like generating a new build number even if no files were modified.

IMPORTANT: Under Windows care must be taken with CR and CRLF line endings. The files build.number and major_version have to be terminated with CRLF, otherwise sed and the other linux/unix utils won't be able to parse them.

Finally here is an example of what build_number.h looks like:

#define BUILD_NUMBER_STR "1234"
#define VERSION_STR "1.0.1234 - Fri Dec 19 11:00:23 HSE 2008"
#define VERSION_STR_SHORT "1.0.1234"

The bash script is easy to modify if any other information is needed, such as build number as a proper integer if some preprocessing is needed.


  1. This comment has been removed by the author.

  2. This comment has been removed by the author.

  3. Thanks for the idea.
    This exact implementation didn't work for me on Windows 8.
    Although I installed Cygwin and added math bc module to it it still didn't increment with "... bc > build.number.temp". More to say, is "+1" is correct or there should be a space between them like "+ 1"? None worked on my system though.
    I also have some issues with mv. At first it shows error about the second operand not being a directory. Then, after adding -T option to mv it stops complaining, but still doesn't work - I get files with names buld.number.temp*, etc, with * in names (have no idea where it comes from).

    Anyway, I used your approach to write my own Windows batch file which does almost the same as your sh script. And it's used as pre-built event in Atmel Studio 7 (which uses Visual Studio 2015 engine).

    If anyone needs this, here's my batch file:
    set /p version=<..\\major_version.txt
    @echo %version%
    set /p old=<..\\build_number.txt
    set /a new=%old%+1
    @echo New build number: %new%
    @echo Version: %version%.%new%
    @echo %new% > ..\\build_number.txt
    echo #ifndef BUILD_NUMBER
    echo #define BUILD_NUMBER %new%U
    echo #endif
    echo #ifndef BUILD_NUMBER_STR
    echo #define BUILD_NUMBER_STR "%new%"
    echo #endif
    echo #ifndef VERSION_FULL_STR
    echo #define VERSION_FULL_STR "%version%.%new%"
    echo #endif
    ) > ..\\build_number.h

    And in Pre-Build event command line you add "$(MSBuildProjectDirectory)\make_buildnum.bat" (no quotation marks).
    Notes: I chose to use one copy of version and build number for both Debug and Release configurations, that's why I place the batch file and both major_version.txt and build_number.txt in project directory, not Debug or Release ones. Also, that's why there's "..\\" before filenames in batch - otherwise pre-build event will try to find files in Debug or Release directory and complain there's no such files.
    Remember to manually create build_number.txt with the number 1 and major_version.txt with any number in it before calling the batch.

    Here's the resulting header file in project folder after calling the exact BAT file I showed earlier:
    #ifndef BUILD_NUMBER
    #define BUILD_NUMBER 24U
    #ifndef BUILD_NUMBER_STR
    #define BUILD_NUMBER_STR "24"
    #ifndef VERSION_FULL_STR
    #define VERSION_FULL_STR "0.9.24"

    Hope this helps anyone.