preprocesamiento directivas c++ include c-preprocessor

c++ - directivas - ¿Se puede usar el preprocesador C para decir si existe un archivo?



ifndef (8)

Cree una carpeta especial para los encabezados que faltan y haga que la última carpeta que se busque sea la última
(eso es compliler específico - último elemento en la variable de entorno "INCLUYE", algo así)

Entonces, si puede faltar algo de header1.h, crea en esa carpeta un stub

header1.h:

#define header1_is_missing

Ahora siempre puedes escribir

#include <header1.h> #ifdef header1_is_missing // there is no header1.h #endif

Tengo una base de código muy grande (léase: miles de módulos) que tiene código compartido en numerosos proyectos que se ejecutan en diferentes sistemas operativos con diferentes compiladores de C ++. Huelga decir que mantener el proceso de compilación puede ser una tarea ardua.

Hay varios lugares en la base de código donde limpiaría el código sustancialmente si hubiera una manera de hacer que el preprocesador ignore ciertos #includes si el archivo no existía en la carpeta actual. ¿Alguien sabe una manera de lograr eso?

Actualmente, usamos un #ifdef alrededor del #include en el archivo compartido, con un segundo archivo específico del proyecto que #include define si el #include existe o no en el proyecto. Esto funciona, pero es feo. A menudo las personas olvidan actualizar adecuadamente las definiciones cuando agregan o eliminan archivos del proyecto. He contemplado la posibilidad de escribir una herramienta de preconstrucción para mantener este archivo actualizado, pero si hay una forma independiente de plataforma para hacer esto con el preprocesador, preferiría hacerlo de esa manera. ¿Algunas ideas?


El preprocesador en sí no puede identificar la existencia de archivos, pero ciertamente puede usar el entorno de compilación para hacerlo. Estoy familiarizado con make, que te permite hacer algo como esto en tu archivo MAKE:

ifdef $(test -f filename && echo "present") DEFINE=-DFILENAME_PRESENT endif

Por supuesto, tendrías que encontrar un análogo para esto en otros entornos de compilación como VisualStudio, pero estoy seguro de que existen.


Hasta donde sé cpp no ​​tiene una directiva con respecto a la existencia de un archivo.

Es posible que pueda lograr esto con un poco de ayuda del Makefile, si está utilizando la misma marca en todas las plataformas. Puede detectar la presencia de un archivo en el Makefile:

foo.o: foo.c if [ -f header1.h ]; then CFLAGS+=-DHEADER1_INC

Como menciona @Greg Hewgill, puedes hacer que tus #includes sean condicionales:

#ifdef HEADER1_INC #include <header1.h> #endif


Otra posibilidad: llene un directorio en alguna parte con versiones de longitud cero de todos los encabezados que desea incluir opcionalmente. Pase un argumento -I a este directorio como la última opción.

El cpp de GCC busca en sus directorios de inclusión en orden, si encuentra un archivo de encabezado en un directorio anterior lo usará. De lo contrario, eventualmente encontrará el archivo de longitud cero y será feliz.

Supongo que otras implementaciones de cpp también buscan en sus directorios de inclusión en el orden especificado.


Podría tener una ejecución de paso previa a la compilación que genere un archivo de inclusión que contenga una lista de #defines que represente los nombres de los archivos existentes en el directorio actual:

#define EXISTS_FILE1_C #define EXISTS_FILE1_H #define EXISTS_FILE2_C

Luego, incluya ese archivo dentro de su código fuente, y luego su fuente puede probar las EXISTS_* para ver si un archivo existe o no.


En general, esto se hace mediante el uso de una secuencia de comandos que intenta ejecutar el preprocesador en un intento de incluir el archivo. Dependiendo de si el preprocesador devuelve un error, el script actualiza un archivo .h generado con un #define apropiado (o #undef). En bash, el script podría verse vagamente así:

cat > .test.h <<''EOM'' #include <asdf.h> EOM if gcc -E .test.h then echo ''#define HAVE_ASDF_H 1'' >> config.h else echo ''#ifdef HAVE_ASDF_H'' >> config.h echo ''# undef HAVE_ASDF_H'' >> config.h echo ''#endif'' >> config.h fi

Un marco bastante completo para trabajar portátilmente con controles de portabilidad como este (y otros miles) es autoconf .


Tenía que hacer algo similar para el sistema operativo Symbian. Así es como lo hice: digamos que desea verificar si el archivo "file_strange.h" existe y desea incluir algunos encabezados o enlaces a algunas bibliotecas, dependiendo de la existencia de ese archivo.

primero crea un pequeño archivo por lotes para verificar la existencia de ese archivo.

autoconf es bueno, pero una muerte excesiva para muchos proyectos pequeños.

---------- check.bat

@echo off IF EXIST [/epoc32/include/domain/middleware/file_strange] GOTO NEW_API GOTO OLD_API GOTO :EOF :NEW_API echo.#define NEW_API_SUPPORTED>../inc/file_strange_supported.h GOTO :EOF :OLD_API echo.#define OLD_API_SUPPORTED>../inc/file_strange_supported.h GOTO :EOF

---------- termina check.bat

luego creé un archivo gnumake

----------checkmedialist.mk

do_nothing : @rem do_nothing MAKMAKE : check.bat BLD : do_nothing CLEAN : do_nothing LIB : do_nothing CLEANLIB : do_nothing RESOURCE : do_nothing FREEZE : do_nothing SAVESPACE : do_nothing RELEASABLES : do_nothing FINAL : do_nothing

----------check.mk finaliza

incluya el archivo check.mk en su archivo bld.inf, DEBE estar delante de sus archivos MMP

PRJ_MMPFILES gnumakefile checkmedialist.mk

ahora en tiempo de compilación, el archivo file_strange_supported.h tendrá un indicador apropiado. puedes usar esta bandera en tus archivos cpp o incluso en el archivo mmp por ejemplo en mmp

#include "../inc/file_strange_supported.h" #ifdef NEW_API_SUPPORTED LIBRARY newapi.lib #else LIBRARY oldapi.lib #endif

y en .cpp

#include "../inc/file_strange_supported.h" #ifdef NEW_API_SUPPORTED CStrangeApi* api = Api::NewLC(); #else // .. #endif


Pequeña actualización

Algunos compiladores pueden ser compatibles con __has_include ( header-name ) .

La extensión se agregó al estándar C ++ 17 ( P0061R1 ).

Ayuda del compilador

  • Sonido metálico
  • GCC desde 5.X
  • Visual Studio de VS2015 Update 2 (?)

Ejemplo (del sitio web clang):

// Note the two possible file name string formats. #if __has_include("myinclude.h") && __has_include(<stdint.h>) # include "myinclude.h" #endif

Fuentes