2

I'm troubleshooting a bit of code that requires a certain version of OpenSSL. If the version number exported by OpenSSL isn't high enough, a warning is returned, and various bits of the program are turned off.

The code looks like this:

#if OPENSSL_VERSION_NUMBER >= 0x10002000
      //code here
#else
#warning "http_auth_ldap: Compiling with OpenSSL < 1.0.2, certificate verification will be unavailable"

Now, say that I wanted to include the reported version number in this message for the benefit of the user.

The docs for CPP say that:

Neither #error nor #warning macro-expands its argument. Internal whitespace sequences are each replaced with a single space. The line must consist of complete tokens. It is wisest to make the argument of these directives be a single string constant; this avoids problems with apostrophes and the like.

This appears to preclude me from just sticking #OPENSSL_VERISON_NUMBER onto the end of the message.

The author of this bit of code tried a stringification method detailed in this question, but it appears to not work:

#// used for manual warnings
#define XSTR(x) STR(x)
#define STR(x) #x

This leads to a warning reading:

warning: http_auth_ldap: Compiling with OpenSSL < 1.0.2, certificate verification will be unavailable. OPENSSL_VERSION_NUMBER == OPENSSL_VERSION_NUMBER [-W#pragma-messages]

..and a build failure. #pragma message appears to suffer from the same no-macro-expansion limitation as #warning.

Is there a sane way to concatenate the version string into the error?

Mikey T.K.
  • 1,112
  • 18
  • 43
  • 1
    Mostly because this is someone else's code I'm trying to understand. I'm getting this warning, but I can't see what it's comparing and failing against to determine if this is a syntax problem or a problem with my build environment. – Mikey T.K. Feb 11 '16 at 19:44
  • There's no `#warning` in the standard C preprocessor. It's an extension offered by gcc. The standard doesn't provide a way to produce diagnostic messages like that. – n. m. could be an AI Feb 11 '16 at 20:11
  • @MikeyT.K.: Sorry, couldn't resist :-) Good you found it, but why not just changed `o` to `e`(mitted)? – too honest for this site Feb 11 '16 at 20:21
  • @n.m.: Well, the standard does provide `#error` which is much the same idea, just at a different severity. Until your comment, I would have bet `#warning` is standard, too. Looks like a major omission to me not to define it. – too honest for this site Feb 11 '16 at 20:25
  • 1
    @Olaf The standard has no concept of warning. The error directive is specified to produce a message that contains the sequence of pp-tokens after the directive and up to newline. So, no expansion. – n. m. could be an AI Feb 12 '16 at 06:04
  • @n.m.: Hmm, Annex I is a strong hint to me. And the standard requires an implementation to emit a diagnostic message for certain situations, e.g. using a function without preceeding prototype (which does not result in UB) or an syntax error (which does). And `#error` already does exist. – too honest for this site Feb 12 '16 at 07:09

1 Answers1

1

Since #warrning is not portable, you can try to exploit other things you know about your implementation.

#define cat(a,b) cat2(a,b)
#define cat2(a,b) a##b

#define FOO 199
#define REQUIRED_FOO 200
#if FOO < REQUIRED_FOO

void cat(cat(FOO_is_,  FOO),
    cat(_required_FOO_is_,  REQUIRED_FOO))()
{
  #warning Busted!
}

#endif

Demo.

Here I exploit the fact that gcc prints the name of the function (after macro expansion!) where the error or warning happens.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243