Esiste un pre-processore C che elimina i blocchi di #ifdef in base a valori definiti / non definiti?

Domanda originale

Quello che mi piacerebbe non è un pre-processore C standard, ma una variazione su di esso che accetterebbe da qualche parte – probabilmente la riga di comando tramite le opzioni -DNAME1 e -UNAME2 – una specifica di quali macro sono definite, e quindi eliminerebbe la morte codice.

Potrebbe essere più facile capire cosa sto cercando con alcuni esempi:

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

Se il comando fosse eseguito con ‘-DNAME1’, l’output sarebbe:

 #define ALBUQUERQUE "ambidextrous" 

Se il comando fosse eseguito con ‘-UNAME1’, l’output sarebbe:

 #define PHANTASMAGORIA "ghostly" 

Se il comando è stato eseguito con nessuna delle due opzioni, l’output sarebbe lo stesso dell’input.

Questo è un caso semplice – spero che il codice possa gestire anche casi più complessi.

Per illustrare con un esempio reale ma ancora semplice:

 #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 */ 

Mi piacerebbe eseguire il comando con -DUSE_VOID -UPLATFORM1 e ottenere l’output:

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

Un altro esempio:

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

Idealmente, mi piacerebbe correre con -UOLDUNIX e ottenere l’output:

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

Questo potrebbe spingere la mia fortuna!

Motivazione: codice base grande e antico con un sacco di codice condizionale. Molte delle condizioni non si applicano più: la piattaforma OLDUNIX, ad esempio, non viene più creata e non è più supportata, quindi non è necessario avere riferimenti nel codice. Altre condizioni sono sempre vere. Ad esempio, le funzionalità vengono aggiunte con la compilazione condizionale in modo che sia ansible utilizzare una singola versione del codice per entrambe le versioni precedenti del software in cui la funzione non è disponibile e le versioni più recenti in cui è disponibile (più o meno). Alla fine, le vecchie versioni senza la funzione non sono più supportate – tutto utilizza la funzionalità – quindi la condizione sulla presenza o meno della funzionalità deve essere rimossa e anche il codice ‘when feature is absent’ deve essere rimosso. Mi piacerebbe avere uno strumento per fare il lavoro automaticamente perché sarà più veloce e più affidabile rispetto a farlo manualmente (che è piuttosto critico quando il codice base include 21.500 file sorgente).

(Una versione molto intelligente dello strumento potrebbe leggere #include ‘d file per determinare se le macro di controllo, quelle specificate da -D o -U sulla riga di comando, sono definite in quei file. Non sono sicuro che sia veramente utile eccetto che come diagnostica di backup, in ogni caso, lo pseudo-pre-processore non deve espandere macro o includere file letteralmente, l’output deve essere simile a, ma in genere più semplice, il codice di input).

Rapporto sullo stato (un anno dopo)

Dopo un anno di utilizzo, sono molto soddisfatto di ” sunifdef ” raccomandato dalla risposta selezionata. Non ha ancora commesso un errore, e non me lo aspetto. L’unico cavillo che ho con esso è stilistico. Dato un input come:

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

ed eseguire con ‘-UC’ (C non è mai definito), l’output è:

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

Questo è tecnicamente corretto perché “&&” si lega più strettamente di “||”, ma è un invito aperto alla confusione. Preferirei che includesse le parentesi attorno alle serie di condizioni “&&”, come nell’originale:

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

Tuttavia, data l’oscurità di alcuni del codice con cui devo lavorare, perché quello di essere il più grande pignolo è un forte complimento; è uno strumento prezioso per me.


The New Kid on the Block

Dopo aver controllato l’inclusione dell’URL nelle informazioni di cui sopra, vedo che (come previsto) c’è un nuovo programma chiamato Coan che è il successore di “sunifdef”. È disponibile su SourceForge ed è stato da gennaio 2010. Lo controllerò … ulteriori rapporti entro la fine dell’anno, o forse l’anno prossimo, o prima o poi mai.

Non conosco assolutamente nulla di C, ma sembra che tu stia cercando qualcosa come unifdef . Si noti che non è stato aggiornato dal 2000, ma esiste un successore chiamato “Son of unifdef” (sunifdef) .

Inoltre puoi provare questo strumento http://coan2.sourceforge.net/

qualcosa come questo rimuoverà i blocchi ifdef:

fonte coan -UYOUR_FLAG –filter c, h –recurse YourSourceTree

Ho usato unifdef anni fa per il tipo di problema che descrivi, e ha funzionato bene. Anche se non è stato aggiornato dal 2000, la syntax del preprocessore ifdefs non è cambiata materialmente da allora, quindi mi aspetto che faccia ciò che vuoi. Suppongo che potrebbero esserci dei problemi di compilazione, sebbene i pacchetti appaiano recenti.

Non ho mai usato sunifdef, quindi non posso commentare direttamente.

Intorno al 2004 ho scritto uno strumento che ha fatto esattamente quello che stai cercando. Non sono mai riuscito a distribuire lo strumento, ma il codice può essere trovato qui:

http://casey.dnsalias.org/exifdef-0.2.zip (che è un collegamento dsl)

Si tratta di circa 1.7k linee e implementa un numero sufficiente di grammatica C per analizzare le istruzioni, i commenti e le stringhe del preprocessore utilizzando bison e flex.

Se hai bisogno di qualcosa di simile a un preprocessore, la soluzione flessibile è Wave (da boost). È una libreria progettata per build strumenti C-preprocessor-like (compresi elementi come i preprocessori C ++ 03 e C ++ 0x). Poiché si tratta di una libreria, puoi collegarti al suo codice di input e output.