Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a C pre-processor which eliminates #ifdef blocks based on values defined/undefined?

Original Question

What I'd like is not a standard C pre-processor, but a variation on it which would accept from somewhere - probably the command line via -DNAME1 and -UNAME2 options - a specification of which macros are defined, and would then eliminate dead code.

It may be easier to understand what I'm after with some examples:

#ifdef NAME1 #define ALBUQUERQUE "ambidextrous" #else #define PHANTASMAGORIA "ghostly" #endif 

If the command were run with '-DNAME1', the output would be:

#define ALBUQUERQUE "ambidextrous" 

If the command were run with '-UNAME1', the output would be:

#define PHANTASMAGORIA "ghostly" 

If the command were run with neither option, the output would be the same as the input.

This is a simple case - I'd be hoping that the code could handle more complex cases too.

To illustrate with a real-world but still simple example:

#ifdef USE_VOID #ifdef PLATFORM1 #define VOID void #else #undef VOID typedef void    VOID; #endif /* PLATFORM1 */ typedef void *  VOIDPTR; #else typedef mint     VOID; typedef char *  VOIDPTR; #endif /* USE_VOID */ 

I'd like to run the command with -DUSE_VOID -UPLATFORM1 and get the output:

#undef VOID typedef void    VOID; typedef void *  VOIDPTR; 

Another example:

#ifndef DOUBLEPAD #if (defined NT) || (defined OLDUNIX) #define DOUBLEPAD 8 #else #define DOUBLEPAD 0 #endif /* NT */ #endif /* !DOUBLEPAD */ 

Ideally, I'd like to run with -UOLDUNIX and get the output:

#ifndef DOUBLEPAD #if (defined NT) #define DOUBLEPAD 8 #else #define DOUBLEPAD 0 #endif /* NT */ #endif /* !DOUBLEPAD */ 

This may be pushing my luck!

Motivation: large, ancient code base with lots of conditional code. Many of the conditions no longer apply - the OLDUNIX platform, for example, is no longer made and no longer supported, so there is no need to have references to it in the code. Other conditions are always true. For example, features are added with conditional compilation so that a single version of the code can be used for both older versions of the software where the feature is not available and newer versions where it is available (more or less). Eventually, the old versions without the feature are no longer supported - everything uses the feature - so the condition on whether the feature is present or not should be removed, and the 'when feature is absent' code should be removed too. I'd like to have a tool to do the job automatically because it will be faster and more reliable than doing it manually (which is rather critical when the code base includes 21,500 source files).

(A really clever version of the tool might read #include'd files to determine whether the control macros - those specified by -D or -U on the command line - are defined in those files. I'm not sure whether that's truly helpful except as a backup diagnostic. Whatever else it does, though, the pseudo-pre-processor must not expand macros or include files verbatim. The output must be source similar to, but usually simpler than, the input code.)

Status Report (one year later)

After a year of use, I am very happy with 'sunifdef' recommended by the selected answer. It hasn't made a mistake yet, and I don't expect it to. The only quibble I have with it is stylistic. Given an input such as:

#if (defined(A) && defined(B)) || defined(C) || (defined(D) && defined(E)) 

and run with '-UC' (C is never defined), the output is:

#if defined(A) && defined(B) || defined(D) && defined(E) 

This is technically correct because '&&' binds tighter than '||', but it is an open invitation to confusion. I would much prefer it to include parentheses around the sets of '&&' conditions, as in the original:

#if (defined(A) && defined(B)) || (defined(D) && defined(E)) 

However, given the obscurity of some of the code I have to work with, for that to be the biggest nit-pick is a strong compliment; it is valuable tool to me.


The New Kid on the Block

Having checked the URL for inclusion in the information above, I see that (as predicted) there is an new program called Coan that is the successor to 'sunifdef'. It is available on SourceForge and has been since January 2010. I'll be checking it out...further reports later this year, or maybe next year, or sometime, or never.

like image 800
Jonathan Leffler Avatar asked Feb 08 '09 06:02

Jonathan Leffler


People also ask

What does C preprocessor do?

The C preprocessor is a macro processor that is used automatically by the C compiler to transform your program before actual compilation. It is called a macro processor because it allows you to define macros, which are brief abbreviations for longer constructs.

Does C preprocessor remove comments?

According to MSDN, comments are replaced with a single space in the tokenization phase, which happens before the preprocessing phase where macros are expanded.

What is pre processors and their use in C give at least 2 examples?

Examples of some preprocessor directives are: #include, #define, #ifndef etc. Remember that the # symbol only provides a path to the preprocessor, and a command such as include is processed by the preprocessor program. For example, #include will include extra code in your program.


2 Answers

I know absolutely nothing about C, but it sounds like you are looking for something like unifdef. Note that it hasn't been updated since 2000, but there is a successor called "Son of unifdef" (sunifdef).

like image 122
Jörg W Mittag Avatar answered Sep 25 '22 01:09

Jörg W Mittag


Also you can try this tool http://coan2.sourceforge.net/

something like this will remove ifdef blocks:

coan source -UYOUR_FLAG --filter c,h --recurse YourSourceTree

like image 31
ernesto Avatar answered Sep 22 '22 01:09

ernesto