Peter Seiderer for http://www.ciselant.de
Incorporate a global Subversion1 revision number as build/revision version in a Qt2 project.
Subversion has the ability to substitute keywords3 e.g. the keyword 'Revision' in a file will be expanded to the last known revision in which the file changed. If you want some GlobalRev as build/revision number in your project some extra work has to be done using the Subversion tool svnversion4.
The following describes four different solutions for a Qt qmake based project checked into a Subversion repository. The first three solutions are based on a generated header 'revision.h' included from the main file 'example.cpp'. The fourth is based on a define directive at compile time.
1 #ifndef version_h 2 #define version_h 3 #define VERSION "1.2.3" 4 #endifA C++ file example.cpp with the main entry point printing the string 'version: <version>-build-<revision>' to stdout:
1 #include "version.h" 2 #include "revision.h" 3 #include <stdio.h> 4 5 int main(int argc, char* argv []) { 6 printf("version: %s-build-%s\n", VERSION, REVISION); 7 return 0; 8 }
1 PRE_TARGETDEPS += $$OUT_PWD/revision.h 2 3 HEADERS = version.h 4 SOURCES = example.cpp 5 TARGET = example 6 7 QMAKE_EXTRA_TARGETS += revtarget 8 revtarget.target = $$OUT_PWD/revision.h 9 revtarget.commands = @echo \"updating file $$revtarget.target\"; \ 10 echo -e \"/* generated file (do not edit) */\\n\" \ 11 \"$$LITERAL_HASH ifndef revision_h\\n\" \ 12 \"$$LITERAL_HASH define revision_h 1\\n\" \ 13 \"$$LITERAL_HASH define REVISION \\\"`svnversion -n $$PWD`\\\"\\n\" \ 14 \"$$LITERAL_HASH endif\" > $$revtarget.target 15 revtarget.depends = FORCE 16 QMAKE_DISTCLEAN += $$revtarget.targetExample of a generated revision.h file:
1 /* generated file (do not edit) */ 2 # ifndef revision_h 3 # define revision_h 1 4 # define REVISION "828" 5 # endifExample output:
version: 1.2.3-build-828for a subversion working directory up to revision r828, or
1.2.3-build-828Mwith local modifications.
The downside of this solution is the every time rebuild of the executable because of the generated file 'revision.h'.
1 PRE_TARGETDEPS += $$OUT_PWD/revision.h 2 3 HEADERS = $$PWD/version.h 4 SOURCES = $$PWD/example.cpp 5 TARGET = example 6 7 QMAKE_EXTRA_TARGETS += revtarget 8 revtarget.target = $$OUT_PWD/revision.h 9 revtarget.commands = @echo \"updating file $$revtarget.target\"; \ 10 echo -e \"/* generated file (do not edit) */\\n\" \ 11 \"$$LITERAL_HASH ifndef revision_h\\n\" \ 12 \"$$LITERAL_HASH define revision_h 1\\n\" \ 13 \"$$LITERAL_HASH define REVISION \\\"`svnversion -n $$PWD`\\\"\\n\" \ 14 \"$$LITERAL_HASH endif\" > $$revtarget.target 15 revtarget.depends = $$SOURCES $$HEADERS $$FORMS $$PWD/example2.pro 16 QMAKE_DISTCLEAN += $$revtarget.target
1 PRE_TARGETDEPS += $$OUT_PWD/revision.h 2 3 HEADERS = version.h 4 SOURCES = example.cpp 5 TARGET = example 6 7 LITERAL_DOLLAR = $ 8 QMAKE_EXTRA_TARGETS += revtarget 9 revtarget.target = $$OUT_PWD/revision.h 10 revtarget.commands = @SVNVERSION=\\\"`svnversion -n $$PWD`\\\"; \ 11 SVNFILEVERSION=`if [ -e $$revtarget.target ]; then \ 12 grep REVISION $$revtarget.target | \ 13 awk \'{ print $${LITERAL_DOLLAR}$${LITERAL_DOLLAR}4 }\' ; \ 14 else echo unknown; fi;`; \ 15 if [ $${LITERAL_DOLLAR}$${LITERAL_DOLLAR}SVNVERSION == \ 16 $${LITERAL_DOLLAR}$${LITERAL_DOLLAR}SVNFILEVERSION ]; \ 17 then \ 18 echo \"svn status not changed - keep file $$revtarget.target\"; \ 19 else \ 20 echo \"svn status changed - updating file $$revtarget.target\"; \ 21 echo -e \"/* generated file (do not edit) */\\n\" \ 22 \"$$LITERAL_HASH ifndef revision_h\\n\" \ 23 \"$$LITERAL_HASH define revision_h 1\\n\" \ 24 \"$$LITERAL_HASH define REVISION \\\"`svnversion -n $$PWD`\\\"\\n\" \ 25 \"$$LITERAL_HASH endif\" > $$revtarget.target; \ 26 fi 27 revtarget.depends = FORCE 28 QMAKE_DISTCLEAN += $$revtarget.targetThis is the only solution which forces a recompile in case of a svn status update without file update (e.g. 'svn update' or 'svn commit').
1 #include "version.h" 2 #include <stdio.h> 3 4 #ifndef REVISION 5 #define REVISION "unknown" 6 #endif 7 8 int main(int argc, char* argv []) { 9 printf("version: %s-build-%s\n", VERSION, REVISION); 10 return 0; 11 }
1 DEFINES += "REVISION=\\\"`svnversion -n $$PWD`\\\"" 2 3 HEADERS = version.h 4 SOURCES = example.cpp 5 TARGET = example 6This approach works only for very small projects (like the given example project) with only one source file. It will fail to update the revision string in case of a multi source file project if the main file does not depend on all other ones.