Existe-t-il un pré-processeur C qui élimine les blocs #ifdef en fonction de valeurs définies / non définies?

Question originale

Ce que je voudrais, ce n’est pas un pré-processeur C standard, mais une variante qui accepterait quelque part – probablement la ligne de commande via les options -DNAME1 et -UNAME2 – une spécification des macros définies, qui éliminerait ensuite les morts. code.

Il sera peut-être plus facile de comprendre ce que je recherche après quelques exemples:

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

Si la commande était exécutée avec ‘-DNAME1’, le résultat serait:

 #define ALBUQUERQUE "ambidextrous" 

Si la commande était exécutée avec ‘-UNAME1’, le résultat serait:

 #define PHANTASMAGORIA "ghostly" 

Si la commande était exécutée sans aucune option, la sortie serait la même que l’entrée.

C’est un cas simple – j’espère que le code pourra également traiter des cas plus complexes.

Pour illustrer avec un exemple réel mais toujours simple:

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

J’aimerais lancer la commande avec -DUSE_VOID -UPLATFORM1 et obtenir le résultat:

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

Un autre exemple:

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

Idéalement, j’aimerais utiliser -UOLDUNIX et obtenir le résultat:

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

Cela peut pousser ma chance!

Motivation: grande base de code ancienne avec beaucoup de code conditionnel. La plupart des conditions ne sont plus remplies – la plate-forme OLDUNIX, par exemple, n’est plus créée ni supscope. Il n’est donc pas nécessaire de faire référence à celle-ci dans le code. Les autres conditions sont toujours vraies. Par exemple, des fonctionnalités sont ajoutées à la compilation conditionnelle afin qu’une seule version du code puisse être utilisée à la fois pour les versions antérieures du logiciel lorsque la fonctionnalité n’est pas disponible et pour les versions plus récentes où il est disponible (plus ou moins). Finalement, les anciennes versions sans fonctionnalité ne sont plus sockets en charge – tout utilise la fonctionnalité -, il faut donc supprimer la condition de présence ou non de la fonctionnalité, ainsi que le code “Lorsque la fonctionnalité est absente”. J’aimerais avoir un outil pour faire le travail automatiquement car il sera plus rapide et plus fiable que de le faire manuellement (ce qui est plutôt critique lorsque la base de code comprend 21 500 fichiers sources).

(Une version très intelligente de l’outil pourrait lire #include ‘d fichiers pour déterminer si les macros de contrôle – celles spécifiées par -D ou -U sur la ligne de commande – sont définies dans ces fichiers. Je ne suis pas sûr que ce soit vraiment utile. Cependant, quel que soit le cas, le pseudo-pré-processeur ne doit pas développer les macros ni inclure de fichiers tels quels, mais le code de sortie doit être identique à celui du code d’entrée, mais généralement plus simple.)

Rapport de situation (un an plus tard)

Après un an d’utilisation, je suis très heureux avec ‘ sunifdef ‘ recommandé par la réponse sélectionnée. Il n’a pas encore commis d’erreur et je ne m’y attendais pas. Le seul petit reproche que je puisse faire est stylistique. Étant donné une entrée telle que:

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

et couru avec ‘-UC’ (C n’est jamais défini), le résultat est:

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

Ceci est techniquement correct car ‘&&’ est plus étroit que ‘||’, mais c’est une invitation ouverte à la confusion. Je préférerais de beaucoup qu’il inclue des parenthèses autour des ensembles de conditions ‘&&’, comme dans l’original:

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

Cependant, étant donné l’obscurité de certains codes avec lesquels je dois travailler, le fait de devenir le plus gros pick-pick est un puissant compliment; c’est un outil précieux pour moi.


Le nouveau gamin sur le bloc

Après avoir vérifié l’URL pour l’inclusion dans les informations ci-dessus, je constate (comme prévu) qu’il existe un nouveau programme appelé Coan qui succède à ‘sunifdef’. Il est disponible sur SourceForge depuis janvier 2010. Je le vérifierai… d’autres rapports plus tard cette année, ou peut-être l’année prochaine, ou parfois, voire jamais.

Je ne sais absolument rien à propos de C, mais il unifdef que vous cherchiez quelque chose comme unifdef . Notez qu’il n’a pas été mis à jour depuis 2000, mais il existe un successeur appelé “Son of unifdef” (sunifdef) .

J’ai utilisé unifdef il y a quelques années pour le type de problème que vous décrivez, et cela a bien fonctionné. Même si elle n’a pas été mise à jour depuis 2000, la syntaxe du préprocesseur ifdefs n’a pas changé de manière significative depuis lors, je suppose donc qu’elle fera toujours ce que vous voulez. Je suppose qu’il peut y avoir des problèmes de compilation, bien que les paquetages semblent récents.

Je n’ai jamais utilisé sunifdef, je ne peux donc pas en parler directement.

Aussi, vous pouvez essayer cet outil http://coan2.sourceforge.net/

quelque chose comme ça va supprimer les blocs ifdef:

source coan -UYOUR_FLAG –filtre c, h –recurse YourSourceTree

Vers 2004, j’ai écrit un outil qui faisait exactement ce que vous cherchiez. Je n’ai jamais eu le temps de dissortingbuer l’outil, mais le code peut être trouvé ici:

http://casey.dnsalias.org/exifdef-0.2.zip (c’est un lien dsl)

Il s’agit d’environ 1,7k lignes et implémente suffisamment de grammaire C pour parsingr les instructions, les commentaires et les chaînes du préprocesseur à l’aide de bison et flex.

Si vous avez besoin de quelque chose de similaire à un préprocesseur, la solution flexible est Wave (de boost). Il s’agit d’une bibliothèque conçue pour créer des outils similaires à ceux du préprocesseur C (notamment les préprocesseurs C ++ 03 et C ++ 0x). Comme il s’agit d’une bibliothèque, vous pouvez vous connecter à ses codes d’entrée et de sortie.