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