Add an Auto-Incrementing Build-Number to Your Build Process
When building software it's often useful to give each iteration of your build process a unique number. Many IDEs and RAD tools do this for you automatically. If yours doesn't and you're using a make file to build your code you can add an auto-incrementing build number to your project with a few simple changes to your make file.
The mechanism presented here does not need to modify your source code at all, it uses linker symbols to add the build number to your program. Note however that you will probably want to modify your source code to display the build number, but that's not strictly necessary.
Let's start with the following simple make file for building a program:
# Makefile
OBJECTS=bnum.o
a.out: $(OBJECTS)
$(CC) $(LDFLAGS) -o $@ $(OBJECTS)
To add the build number to the make file we set the variable BUILD_NUMBER_FILE to the name of a file that will contain our build number value. Then we add BUILD_NUMBER_FILE to the dependencies for a.out, add BUILD_NUMBER_LDFLAGS to the flags used when linking the program, and finally include the file buildnumber.mak at the end of the make file. The converted make file looks like:
# Makefile
# Name of text file containing build number.
BUILD_NUMBER_FILE=build-number.txt
OBJECTS=bnum.o
a.out: $(OBJECTS) $(BUILD_NUMBER_FILE)
$(CC) $(LDFLAGS) $(BUILD_NUMBER_LDFLAGS) -o $@ $(OBJECTS)
# Include build number rules.
include buildnumber.mak
The included file buildnumber.mak looks like:
# Create an auto-incrementing build number.
BUILD_NUMBER_LDFLAGS = -Xlinker --defsym -Xlinker __BUILD_DATE=$$(date +'%Y%m%d')
BUILD_NUMBER_LDFLAGS += -Xlinker --defsym -Xlinker __BUILD_NUMBER=$$(cat $(BUILD_NUMBER_FILE))
# Build number file. Increment if any object file changes.
$(BUILD_NUMBER_FILE): $(OBJECTS)
@if ! test -f $(BUILD_NUMBER_FILE); then echo 0 > $(BUILD_NUMBER_FILE); fi
@echo $$(($$(cat $(BUILD_NUMBER_FILE)) + 1)) > $(BUILD_NUMBER_FILE)
The linker flags cause the linker to create two symbols: __BUILD_NUMBER and __BUILD_DATE which will be equal to the build number and the build-date respectively. The build-date is set using the standard date command. The build number is simply the value contained in the build number file, which is extracted using the standard cat command.
The make rule for the build number file depends on all the project object files and if any of them changes the build number is incremented by executing the following commands:
if ! test -f build-number.txt; then echo 0 > build-number.txt; fi
echo $(($(cat build-number.txt) + 1)) > build-number.txt
The test program bnum.c merely writes out the build number and build-date:
#include <stdio.h>
extern char __BUILD_DATE;
extern char __BUILD_NUMBER;
main()
{
printf("Build date : %u\n", (unsigned long) &__BUILD_DATE);
printf("Build number: %u\n", (unsigned long) &__BUILD_NUMBER);
}
A sample of iterative builds is shown below:
$ rm bnum.o; make cc -c -o bnum.o bnum.c cc -Xlinker --defsym -Xlinker __BUILD_DATE=$(date +'%Y%m%d') \ -Xlinker --defsym -Xlinker __BUILD_NUMBER=$(cat build-number.txt) -o a.out bnum.o $ ./a.out Build date : 20080708 Build number: 24 $ rm bnum.o; make cc -c -o bnum.o bnum.c cc -Xlinker --defsym -Xlinker __BUILD_DATE=$(date +'%Y%m%d') \ -Xlinker --defsym -Xlinker __BUILD_NUMBER=$(cat build-number.txt) -o a.out bnum.o $ ./a.out Build date : 20080708 Build number: 25
One caveat to an auto-incrementing build number is that just because you have two versions of a program with different build numbers it does not mean they are functionally different. If you routinely run make clean; make all just for fun, you'll get a new build number but nothing will have changed.