Recursing macro preprocessing?

H

Henrik Goldman

I have an application which compiles on a number of different platforms. Now
I'm trying to incorporate an external library which is only available to a
subset of the platforms that my application support.
This is ok as it will give increased usability on some platforms but not
all.

The problem however is to remove code at compiletime when my application is
compiled on a platform which does not support this library.

Using the preprocessor I can enumerate all the platforms on which this
library support like:

#if (defined(_WIN32) && defined(_M_IX86)) || \

(defined(_WIN64) && defined(_M_AMD64)) || \

(defined(__APPLE__) && defined(__ppc__)) || \

(defined(__APPLE__) && defined(__i386__)) || \

....

#endif

However in those places of my application where the support code to use the
library is defined I'd like to condtionally enable the code on a platform
where support is present.

More specifically I'd like to do:



INCLUDE_MY_LIB_SUPPORT_START

printf("This platform has library support\n");

INCLUDE_MY_LIB_SUPPORT_END

On platforms with library support it the macro would expand to nothing. On
unsupported platforms it would expand to #if 0 and #endif and thus removed
by the compiler.

The first few tests showed however that this is not easily possible. The
alternative is then something like:

#ifdef INCLUDE_MY_LIB_SUPPORT

printf("This platform has library support\n");

#endif

This is not as good however as one can easily forget to include the needed
header file and then you get no warning but code on supported platforms will
still be removed.

Is there a way to solve this? One other thing is to define it at compile
time through a switch like -DMY_LIB_SUPPORT but I'd like to keep down the
number of switches on commandline.

Thanks.

-- Henrik
 
K

Kaz Kylheku

Henrik said:
On platforms with library support it the macro would expand to nothing. On
unsupported platforms it would expand to #if 0 and #endif and thus removed
by the compiler.

Not possible. It is not possible to produce a preprocessing directive
using preprocessing. If you produce the tokens ``#if 0'', they will not
be treated as a preprocessing directive, even though they look like
one.
The first few tests showed however that this is not easily possible. The
alternative is then something like:

#ifdef INCLUDE_MY_LIB_SUPPORT

printf("This platform has library support\n");

#endif

This is not as good however as one can easily forget to include the needed
header file and then you get no warning but code on supported platforms will
still be removed.

Use integer values, instead of testing for symbol existence:

#if INCLUDE_MY_LIB_SUPPORT
#endif

Now you either have

#define INCLUDE_MY_SUPPORT 0

or

#define INCLUDE_MY_SUPPORT 1

If you forget to define it, then the #if is ill-formed, having no
expression.
 
G

Greg Comeau

#if INCLUDE_MY_LIB_SUPPORT
#endif

Now you either have

#define INCLUDE_MY_SUPPORT 0

or

#define INCLUDE_MY_SUPPORT 1

If you forget to define it, then the #if is ill-formed, having no
expression.

Fairly certain in the case above it is well formed as any ids
not replaced become replaced by a 0 token.
 
K

Kaz Kylheku

Greg said:
#if INCLUDE_MY_LIB_SUPPORT
#endif [ snip ]
If you forget to define it, then the #if is ill-formed, having no
expression.

Fairly certain in the case above it is well formed as any ids
not replaced become replaced by a 0 token.

Ah crap, right.

Then, to defeat all this defaulting, you can to impose an enumeration.
For instance, the rule that two symbols must be defined:

#if defined INCLUDE_MY_SUPPORT
...
#elif !defined NO_INCLUDE_MY_SUPPORT
#error must explicitly request no support
#endif

The obvious alternative way to solve the original problem is to create
an API which is always defined, and always called. On the subset of the
platforms that have the special library, the API calls the library. On
the platforms where it doesn't, the API is just stubs that do the right
kind of nothing for each function.

// In the header file

#if .. test for all the platforms where library is supported ...
// #include or otherwise define the library API
int library_function();
#else
// define dummy version of the API which does nothing, using inline
functions
inline int library_function() { return 0; }
// or, using macros:
#define library_function() ((int) 0)
#endif

And so now there is no special dance to repeat in the sources, where
you simply call the function:

library_function(); // might do nothing if not supported

This also takes care of the forgotten header include.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top