views:

225

answers:

6

I am looking for a C/C++ macro that can transform a random SVN revision like "$Revision: 9 $" or "$Revision: 9999999 $" into an integer or a string.

I know that simple functions exists to achieve this, but I want this to be made at compile time.

My wish is to write things like:unsigned int rev = SVN_TO_INT("$Revision$");

+2  A: 

I'm relatively sure that this isn't possible with a macro.

It may be possible with template metaprogramming, but I've never gone near it.

It would also be possible with a pre-build script that replaces SVN_TO_INT with your desired text.

I don't understand why you want this, though, since it would be just as easy to hardcode the version number since you know it at compile time.

dauphic
Yeah but it's a pain to change it every time :)
Jacob
You can actually hack together a script which will run in the makefile or so and put a -DSVN_REVISION=89278 into the command line.
Joey
+1 for basically "why if you can do it before compilation" which i was to preoccupied to think of.
Georg Fritzsche
+1  A: 

You can't fully work with strings at preprocessing or compile time - but why not use something something like:

int svn_version() 
{
     static const int v = extract_svn_version(REVISION);
     return v;
}
Georg Fritzsche
I want to avoid the revision string to be stored in my binary file ("$Revision: XXXX $")
Soubok
Then you have to do it outside of your source and define it in the build enviroment - even though in C++0x there seems to be compile time string processing (before that there is none) i guess that still doesn't guarantee that the string literal will be eliminated from the binary - the compiler may or may not do that.
Georg Fritzsche
Why don't you want it in your binary file? What we used to use that for (in CVS) was so we could find the build information on a binary. Once the binaries went to the customers, we had no control over where they went, and it was sometimes real useful to know which version a certain customer system was running.
David Thornley
+2  A: 

You can't do the kind of string manipulation you want at compile time with the C preprocessor (macros) or with templates (C++). You'll need to use an external utility or script that you can invoke from the build process.

Some utilities/scripts/code that might help you:

Michael Burr
+5  A: 

I agree that you can't work with strings at compile time through macros or templates. So.... don't use strings.

This is an ugly hack, but I think it meets all your requirements. I don't recommend it.

#define $Revision struct REV_STR { unsigned foo
#define $ * 64; };

$Revision: 4521 $

enum { REV = sizeof(REV_STR) / 8 };

#undef $Revision
#undef $

#include <iostream>
int main()
{
   std::cout << REV << std::endl;
   return 0;
}

// $ g++ -Wall -Wextra revision.cpp && ./a.exe
// revision.cpp:4: warning: width of `REV_STR::foo' exceeds its type
// 4521
Dan
That's beautifully disgusting, and I salute you for it!
caf
Respect!I love it! Although i would recommend anyone against writing anything like it.
dudico
+1  A: 

I agree that it is not doable with macros, however, I found a trick using compiler optimizations. The result is that the expression JL_SvnRevToInt("$Revision: 12345 $") is reduced to a single unsigned integer: 12345

inline unsigned int JL_SvnRevToInt(const char *r) {


    if ( r == NULL || r[0] == '\0' || r[10] == '\0' || r[11] == '\0' || r[12] == '\0' || r[13] == '\0' )
    return 0;

    const unsigned int count = 
       r[11] == ' ' ? 1
     : r[12] == ' ' ? 10
     : r[13] == ' ' ? 100
     : r[14] == ' ' ? 1000
     : r[15] == ' ' ? 10000
     : r[16] == ' ' ? 100000
     : r[17] == ' ' ? 1000000
     : r[18] == ' ' ? 10000000
     : r[19] == ' ' ? 100000000
     : 0;

    return
     (r[11] == ' ' ? 0 : (r[11]-'0') * (count/10) +
     (r[12] == ' ' ? 0 : (r[12]-'0') * (count/100) + 
     (r[13] == ' ' ? 0 : (r[13]-'0') * (count/1000) + 
     (r[14] == ' ' ? 0 : (r[14]-'0') * (count/10000) + 
     (r[15] == ' ' ? 0 : (r[15]-'0') * (count/100000) +
     (r[16] == ' ' ? 0 : (r[16]-'0') * (count/1000000) +
     (r[17] == ' ' ? 0 : (r[17]-'0') * (count/10000000) +
     (r[18] == ' ' ? 0 : (r[18]-'0') * (count/100000000) +
     (r[19] == ' ' ? 0 : (r[19]-'0') * (count/1000000000) +
     0)))))))));
}

It supports9 digits revision number, NULL and empty and "$Revision$" strings.

Soubok
+1  A: 

If you have a makefile based build system you can make a special rule that creates a file every make time.

.PHONY: svn_revision.c

svn_revision.c:
        echo -n "int svn_revision = " > svn_revision.c
        svn info | grep Revision | cut -f2 -d" " >> svn_revision.c
        echo ";"  >> svn_revision.c

svn_revision.o: svn_revision.c
epatel