How to check a value like "#define VERSION 3.1.4" at compile time?

I am adding compile-time checks to my C ++ projects to make sure that third-party libraries on all development machines and build servers are updated. Most libraries define something like the following, for example. version 3.1.4:

#define VERSION_MAJOR 3 #define VERSION_MINOR 1 #define VERSION_BUILD 4 

This is convenient and easy to verify using the static_assert directives or preprocessor.

Now I look at a third-party library that defines only one macro:

 #define VERSION 3.1.4 

How can I check the value of such a macro at compile time?


With C ++ 11, I could use the constexpr string comparison function and constexpr macro to test it:

 constexpr bool static_equal(const char * a, const char * b) { return (*a == *b) && (*a == '\0' || static_equal(a + 1, b + 1)); } // stringification functions #define str(x) #x #define xstr(x) str(x) static_assert(static_equal(xstr(VERSION), "3.1.4"), "incorrect version of libwhatever"); 

But we use Visual Studio 2013 on Windows machines, so I can only use the subset of C ++ 11 that it supports. Unfortunately, constexpr not supported.

+7
c ++ c-preprocessor c ++ 11
source share
3 answers

Here is what I am doing now:

 #define str(x) #x #define xstr(x) str(x) #include xstr(libwhatever.version.is.VERSION.should.be.3.1.4) 

Along with this, I add an empty file to the project called libwhatever.version.is.3.1.4.should.be.3.1.4 . Therefore, if the version is correct, the preprocessor will successfully include this file. Otherwise, it will not work with β€œCan not open” libwhatever.version.is.2.7.2.should.be.3.1.4 ', there is no such file or directory. "And the failure of the assembly with a somewhat meaningful message is that considered at the end.

Of course, this approach is not very flexible; for example, I cannot check the minimum version or a number of versions. But for me it is enough to check the exact value.

This is similar to working with Visual C ++ as well as with g ++. I am not sure that the behavior is fully defined according to the standard.

+2
source share

You cannot in the preprocessor, but you can abuse character traits!

VS 2013 seems to support variation patterns. Try using the CSTRING macro at fooobar.com/questions/52916 / ... (you can replace constexpr with const and have the code still working) and do something like:

 #define STRT(x) decltype(CSTRING(x)) static_assert(std::is_same<STRT(VERSION), STRT("3.1.4")>::value, "incorrect version of libwhatever"); 

EDIT: This does not work. However, if your compiler compiles this without errors:

 extern const char data[] = "abc"; template <char C> struct x { static const char c = C; }; char buf[(int)x<"ABC123"[0]>::c]; int main() { return (int)buf; } 

Then you can try the following:

 #include <type_traits> #define VERSION 1.2.3 #define STR2(x) #x #define STR(x) STR2(x) template <char...> struct ststring; // https://stackoverflow.com/a/15860416/2097780 #define MACRO_GET_1(str, i) \ (sizeof(str) > (i) ? str[(i)] : 0) #define MACRO_GET_4(str, i) \ MACRO_GET_1(str, i+0), \ MACRO_GET_1(str, i+1), \ MACRO_GET_1(str, i+2), \ MACRO_GET_1(str, i+3) #define MACRO_GET_16(str, i) \ MACRO_GET_4(str, i+0), \ MACRO_GET_4(str, i+4), \ MACRO_GET_4(str, i+8), \ MACRO_GET_4(str, i+12) #define MACRO_GET_64(str, i) \ MACRO_GET_16(str, i+0), \ MACRO_GET_16(str, i+16), \ MACRO_GET_16(str, i+32), \ MACRO_GET_16(str, i+48) #define MACRO_GET_STR(str) MACRO_GET_64(str, 0), 0 static_assert(std::is_same<ststring<MACRO_GET_STR(STR(VERSION))>, ststring<MACRO_GET_STR("1.2.3")>>::value, "invalid library version"); 
+1
source share

If you right-click on your project-> Properties-> Build Events-> Pre-Build, you will see the "Command Prompt" option. You can put the call into another program here.

You can write another C ++ program or any other language that you prefer that checks your file (or any number of files you want) for "#define VERSION 3.1.4". You can interrupt your build and put any warnings you want into this program.

here is the tutorial: https://dillieodigital.wordpress.com/2012/11/27/quick-tip-aborting-builds-in-visual-studio-based-on-file-contents/

: https://msdn.microsoft.com/en-us/library/e85wte0k.aspx

I tried to mess around with preprocessor commands for a long time, and I could not find a way to do this using only preprocessor commands.

+1
source share

All Articles