Reputation: 15370
I am trying to figure out what version of Boost my code thinks it's using. I want to do something like this:
#error BOOST_VERSION
but the preprocessor does not expand BOOST_VERSION.
I know I could print it out at run-time from the program, and I know I could look at the output of the preprocessor to find the answer. I feel like having a way of doing this during compilation could be useful.
Upvotes: 209
Views: 202156
Reputation: 52449
This is an extension of @Jackie Yeh's answer here.
The magic helper macros, with my minor tweaks:
// Helper macros to print the value of a macro at compile-time
#define VALUE_TO_STRING(x) #x
#define VALUE(x) VALUE_TO_STRING(x)
#define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
To use them:
#pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_INT)
A word of caution: if the macro is not defined, its name will just be printed out again! So, if your macro is called MY_MACRO
, but you never define it, then doing this:
#pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_MACRO)
...will print out something like this:
../main.c:1000:63: note: #pragma message: MY_MACRO=`MY_MACRO`
So, do a search for #pragma message:
in your build output to see the printed macro values. And, look for MY_MACRO=`MY_MACRO`
type output when compiling as a clear sign that MY_MACRO
is not defined!
This threw me off for a while and I lost a lot of time not realizing this.
I want to show that this works with code blocks too. So, here's my full example:
macro_print_macro_values_at_compile_time.c
from my eRCaGuy_hello_world repo:
///usr/bin/env ccache gcc -Wall -Wextra -Werror -O3 -std=gnu17 "$0" -o /tmp/a -lm && /tmp/a "$@"; exit
// For the line just above, see my answer here: https://stackoverflow.com/a/75491834/4561887
#include <stdbool.h> // For `true` (`1`) and `false` (`0`) macros in C
#include <stdint.h> // For `uint8_t`, `int8_t`, etc.
#include <stdio.h> // For `printf()`
// Various macro definitions to test
#define DEFINED_BUT_NO_VALUE
#define MY_INT 3
#define MY_STR "ABC"
#define MY_CODE_BLOCK \
do \
{ \
printf("Hi 1.\n"); \
} while (0)
//
// NB: the `#pragma message` output of the above macro is substantially different if I define it as
// `MY_CODE_BLOCK()` instead, and call it as such inside `main()`! Try it out and you'll see.
//
#define MY_CODE_BLOCK2 \
{ \
printf("Hi 2.\n"); \
}
// Helper macros to print the value of a macro at compile-time
#define VALUE_TO_STRING(x) #x
#define VALUE(x) VALUE_TO_STRING(x)
#define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
// Example prints at compile-time
#pragma message PRINT_MACRO_AT_COMPILE_TIME(NOT_DEFINED)
#pragma message PRINT_MACRO_AT_COMPILE_TIME(DEFINED_BUT_NO_VALUE)
#pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_INT)
#pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_STR)
#pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_CODE_BLOCK)
#pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_CODE_BLOCK2)
// int main(int argc, char *argv[]) // alternative prototype
int main()
{
MY_CODE_BLOCK;
MY_CODE_BLOCK2;
printf("Hello World.\n\n");
return 0;
}
Build and run commands, and output, in both C and C++:
In C:
eRCaGuy_hello_world/c$ ./macro_print_macro_values_at_compile_time.c
./macro_print_macro_values_at_compile_time.c:74:9: note: ‘#pragma message: NOT_DEFINED=`NOT_DEFINED`’
74 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(NOT_DEFINED)
| ^~~~~~~
./macro_print_macro_values_at_compile_time.c:75:9: note: ‘#pragma message: DEFINED_BUT_NO_VALUE=``’
75 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(DEFINED_BUT_NO_VALUE)
| ^~~~~~~
./macro_print_macro_values_at_compile_time.c:76:9: note: ‘#pragma message: MY_INT=`3`’
76 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_INT)
| ^~~~~~~
./macro_print_macro_values_at_compile_time.c:77:9: note: ‘#pragma message: MY_STR=`"ABC"`’
77 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_STR)
| ^~~~~~~
./macro_print_macro_values_at_compile_time.c:78:9: note: ‘#pragma message: MY_CODE_BLOCK=`do { printf("Hi 1.\n"); } while (0)`’
78 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_CODE_BLOCK)
| ^~~~~~~
./macro_print_macro_values_at_compile_time.c:79:9: note: ‘#pragma message: MY_CODE_BLOCK2=`{ printf("Hi 2.\n"); }`’
79 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_CODE_BLOCK2)
| ^~~~~~~
Hi 1.
Hi 2.
Hello World.
Or, in C++:
eRCaGuy_hello_world/c$ g++ -Wall -Wextra -Werror -O3 -std=gnu++17 macro_print_macro_values_at_compile_time.c -o bin/a && bin/a
macro_print_macro_values_at_compile_time.c:71:63: note: ‘#pragma message: NOT_DEFINED=`NOT_DEFINED`’
71 | #define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
| ^~~
macro_print_macro_values_at_compile_time.c:74:17: note: in expansion of macro ‘PRINT_MACRO_AT_COMPILE_TIME’
74 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(NOT_DEFINED)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
macro_print_macro_values_at_compile_time.c:71:63: note: ‘#pragma message: DEFINED_BUT_NO_VALUE=``’
71 | #define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
| ^~~
macro_print_macro_values_at_compile_time.c:75:17: note: in expansion of macro ‘PRINT_MACRO_AT_COMPILE_TIME’
75 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(DEFINED_BUT_NO_VALUE)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
macro_print_macro_values_at_compile_time.c:71:63: note: ‘#pragma message: MY_INT=`3`’
71 | #define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
| ^~~
macro_print_macro_values_at_compile_time.c:76:17: note: in expansion of macro ‘PRINT_MACRO_AT_COMPILE_TIME’
76 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_INT)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
macro_print_macro_values_at_compile_time.c:71:63: note: ‘#pragma message: MY_STR=`"ABC"`’
71 | #define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
| ^~~
macro_print_macro_values_at_compile_time.c:77:17: note: in expansion of macro ‘PRINT_MACRO_AT_COMPILE_TIME’
77 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_STR)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
macro_print_macro_values_at_compile_time.c:71:63: note: ‘#pragma message: MY_CODE_BLOCK=`do { printf("Hi 1.\n"); } while (0)`’
71 | #define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
| ^~~
macro_print_macro_values_at_compile_time.c:78:17: note: in expansion of macro ‘PRINT_MACRO_AT_COMPILE_TIME’
78 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_CODE_BLOCK)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
macro_print_macro_values_at_compile_time.c:71:63: note: ‘#pragma message: MY_CODE_BLOCK2=`{ printf("Hi 2.\n"); }`’
71 | #define PRINT_MACRO_AT_COMPILE_TIME(var) #var "=`" VALUE(var) "`"
| ^~~
macro_print_macro_values_at_compile_time.c:79:17: note: in expansion of macro ‘PRINT_MACRO_AT_COMPILE_TIME’
79 | #pragma message PRINT_MACRO_AT_COMPILE_TIME(MY_CODE_BLOCK2)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
Hi 1.
Hi 2.
Hello World.
sizeof()
) a type or variable in an error message at compile time in both C and C++Upvotes: 1
Reputation: 2590
I know that this is a long time after the original query, but this may still be useful.
This can be done in GCC using the stringify operator "#", but it requires two additional stages to be defined first.
#define XSTR(x) STR(x)
#define STR(x) #x
The value of a macro can then be displayed with:
#pragma message "The value of ABC: " XSTR(ABC)
See: 3.4 Stringification in the gcc online documentation.
How it works:
The preprocessor understands quoted strings and handles them differently from normal text. String concatenation is an example of this special treatment. The message pragma requires an argument that is a quoted string. When there is more than one component to the argument then they must all be strings so that string concatenation can be applied. The preprocessor can never assume that an unquoted string should be treated as if it were quoted. If it did then:
#define ABC 123
int n = ABC;
would not compile.
Now consider:
#define ABC abc
#pragma message "The value of ABC is: " ABC
which is equivalent to
#pragma message "The value of ABC is: " abc
This causes a preprocessor warning because abc (unquoted) cannot be concatenated with the preceding string.
Now consider the preprocessor stringize (Which was once called stringification, the links in the documentation have been changed to reflect the revised terminology. (Both terms, incidentally, are equally detestable. The correct term is, of course, stringifaction. Be ready to update your links.)) operator. This acts only on the arguments of a macro and replaces the unexpanded argument with the argument enclosed in double quotes. Thus:
#define STR(x) #x
char *s1 = "abc";
char *s2 = STR(abc);
will assign identical values to s1 and s2. If you run gcc -E you can see this in the output. Perhaps STR would be better named something like ENQUOTE.
This solves the problem of putting quotes around an unquoted item, the problem now is that, if the argument is a macro, the macro will not be expanded. This is why the second macro is needed. XSTR expands its argument, then calls STR to put the expanded value into quotes.
Upvotes: 240
Reputation: 2727
#define a <::BOOST_VERSION>
#include a
MSVC2015: fatal error C1083: Cannot open include file: '::106200': No such file or directory
Pros:
preprocess to file
is enabled, even if invalid tokens are present:#define a <::'*/`#>
#include a
MSVC2015: fatal error C1083: Cannot open include file: '::'*/`#': No such file or directory
GCC4.x: warning: missing terminating ' character [-Winvalid-pp-token]
#define a <::'*/`#>
Cons:
Update:
For GCC 4.7.x and lower the output throws the error:
error: #include expects "FILENAME" or <FILENAME>
To fix that you can change the prefix:
#define a <.__cplusplus>
#include a
fatal error: .201103L: No such file or directory
Upvotes: 6
Reputation: 305
Instead of #error, try redefining the macro, just before it is being used. Compilation will fail and compiler will provide the current value it thinks applies to the macro.
#define BOOST_VERSION blah
Upvotes: 0
Reputation: 2319
In Microsoft C/C++, you can use the built-in _CRT_STRINGIZE()
to print constants. Many of my stdafx.h
files contain some combination of these:
#pragma message("_MSC_VER is " _CRT_STRINGIZE(_MSC_VER))
#pragma message("_MFC_VER is " _CRT_STRINGIZE(_MFC_VER))
#pragma message("_ATL_VER is " _CRT_STRINGIZE(_ATL_VER))
#pragma message("WINVER is " _CRT_STRINGIZE(WINVER))
#pragma message("_WIN32_WINNT is " _CRT_STRINGIZE(_WIN32_WINNT))
#pragma message("_WIN32_IE is " _CRT_STRINGIZE(_WIN32_IE))
#pragma message("NTDDI_VERSION is " _CRT_STRINGIZE(NTDDI_VERSION))
and outputs something like this:
_MSC_VER is 1915
_MFC_VER is 0x0E00
_ATL_VER is 0x0E00
WINVER is 0x0600
_WIN32_WINNT is 0x0600
_WIN32_IE is 0x0700
NTDDI_VERSION is 0x06000000
Upvotes: 13
Reputation: 171
Without boost :
define same macro again and compiler HIMSELF will give warning.
From warning you can see location of the previous definition.
vi file of previous definition .
ambarish@axiom:~/cpp$ g++ shiftOper.cpp
shiftOper.cpp:7:1: warning: "LINUX_VERSION_CODE" redefined
shiftOper.cpp:6:1: warning: this is the location of the previous definition
#define LINUX_VERSION_CODE 265216
#define LINUX_VERSION_CODE 666
int main ()
{
}
Upvotes: 15
Reputation: 1627
BOOST_PP_STRINGIZE
seems a excellent solution for C++, but not for regular C.
Here is my solution for GNU CPP:
/* Some test definition here */
#define DEFINED_BUT_NO_VALUE
#define DEFINED_INT 3
#define DEFINED_STR "ABC"
/* definition to expand macro then apply to pragma message */
#define VALUE_TO_STRING(x) #x
#define VALUE(x) VALUE_TO_STRING(x)
#define VAR_NAME_VALUE(var) #var "=" VALUE(var)
/* Some example here */
#pragma message(VAR_NAME_VALUE(NOT_DEFINED))
#pragma message(VAR_NAME_VALUE(DEFINED_BUT_NO_VALUE))
#pragma message(VAR_NAME_VALUE(DEFINED_INT))
#pragma message(VAR_NAME_VALUE(DEFINED_STR))
Above definitions result in:
test.c:10:9: note: #pragma message: NOT_DEFINED=NOT_DEFINED
test.c:11:9: note: #pragma message: DEFINED_BUT_NO_VALUE=
test.c:12:9: note: #pragma message: DEFINED_INT=3
test.c:13:9: note: #pragma message: DEFINED_STR="ABC"
For "defined as interger", "defined as string", and "defined but no value" variables , they work just fine. Only for "not defined" variable, they displayed exactly the same as original variable name. You have to used to it -- or maybe someone can provide a better solution.
Upvotes: 137
Reputation: 7378
If you are using Visual C++, you can use #pragma message
:
#include <boost/preprocessor/stringize.hpp>
#pragma message("BOOST_VERSION=" BOOST_PP_STRINGIZE(BOOST_VERSION))
Edit: Thanks to LB for link
Apparently, the GCC equivalent is (not tested):
#pragma message "BOOST_VERSION=" BOOST_PP_STRINGIZE(BOOST_VERSION)
Upvotes: 62
Reputation: 7929
Take a look at the Boost documentation as well, regarding how you are using the macro:
In reference to BOOST_VERSION
, from http://www.boost.org/doc/libs/1_37_0/libs/config/doc/html/boost_config/boost_macro_reference.html#boost_config.boost_macro_reference.boost_helper_macros:
Describes the boost version number in XXYYZZ format such that:
(BOOST_VERSION % 100)
is the sub-minor version,((BOOST_VERSION / 100) %
1000)
is the minor version, and(BOOST_VERSION / 100000)
is the major version.
Upvotes: 1
Reputation: 2511
As far as I know '#error' only will print strings, in fact you don't even need to use quotes.
Have you tried writing various purposefully incorrect code using "BOOST_VERSION"? Perhaps something like "blah[BOOST_VERSION] = foo;" will tell you something like "string literal 1.2.1 cannot be used as an array address". It won't be a pretty error message, but at least it'll show you the relevant value. You can play around until you find a compile error that does tell you the value.
Upvotes: 15
Reputation: 2340
BOOST_VERSION is defined in the boost header file version.hpp.
Upvotes: 1
Reputation: 24890
Looking at the output of the preprocessor is the closest thing to the answer you ask for.
I know you've excluded that (and other ways), but I'm not sure why. You have a specific enough problem to solve, but you have not explained why any of the "normal" methods don't work well for you.
Upvotes: 3
Reputation: 35925
You could also preprocess the source file and see what the preprocessor value evaluates to.
Upvotes: 3
Reputation: 1211
Are you looking for
#if BOOST_VERSION != "1.2"
#error "Bad version"
#endif
Not great if BOOST_VERSION is a string, like I've assumed, but there may also be individual integers defined for the major, minor and revision numbers.
Upvotes: 3
Reputation: 75389
You could write a program that prints out BOOST_VERSION
and compile and run it as part of your build system. Otherwise, I think you're out of luck.
Upvotes: 2