Pregunta

Tengo una base de código muy grande (leída: miles de módulos) que tiene código compartido en numerosos proyectos que se ejecutan en diferentes sistemas operativos con diferentes compiladores de C ++. No hace falta decir que mantener el proceso de construcción puede ser una tarea difícil.

Hay varios lugares en la base de código donde se limpiaría el código sustancialmente si solo hubiera una manera de hacer que el preprocesador ignore ciertos #includes si el archivo no existiera en el 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 # define si o no el #include existe en el proyecto. Esto funciona, pero es feo. Las personas a menudo se olvidan de actualizar correctamente las definiciones cuando agregan o eliminan archivos del proyecto. He contemplado escribir una herramienta de construcción previa para mantener este archivo actualizado, pero si hay una manera independiente de la plataforma de hacer esto con el preprocesador, preferiría hacerlo de esa manera. ¿Alguna idea?

¿Fue útil?

Solución

En general, esto se hace usando un script 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 (o #undef) apropiado. En bash, el script puede 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 de manera portátil con controles de portabilidad como este (y otros miles) es autoconf .

Otros consejos

Pequeña actualización

Algunos compiladores pueden admitir __has_include (nombre-encabezado) .

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

Compilación Compatibilidad

  • Clang
  • GCC desde 5.X
  • Visual Studio de la actualización 2 de VS2015 (?)

Ejemplo (del sitio web de Clang):

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

Fuentes

Cree una carpeta especial para los encabezados faltantes y haga que la carpeta se busque por última vez
(que es específico del compliler: el último elemento en " INCLUYE " variable de entorno, algo así)

Luego, si puede faltar algo de header1.h, cree en esa carpeta un talón

header1.h:

#define header1_is_missing

Ahora siempre puedes escribir

#include <header1.h>
#ifdef header1_is_missing

   // there is no header1.h 

#endif

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, lo que te permitiría hacer algo como esto en tu makefile:

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

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

Podría tener una ejecución previa de compilación que genere un archivo de inclusión que contenga una lista de #defines que representan 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 el EXISTS_ * que se define para ver si un archivo existe o no.

Por lo que sé, cpp no ??tiene una directiva sobre la existencia de un archivo.

Podrías lograr esto con un poco de ayuda de Makefile, si estás usando 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 lo menciona @Greg Hewgill, puedes hacer que tus #includes sean condicionales:

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

Otra posibilidad: rellenar un directorio en algún lugar 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 GCC cpp busca 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 sus directorios de inclusión en el orden especificado.

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.

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

autoconf es bueno, pero es un gran problema 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

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

luego creé un archivo gnumake

----------checkmedialial.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 termina

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

PRJ_MMPFILES
gnumakefile checkmedialist.mk

ahora en tiempo de compilación, el archivo file_strange_supported.h tendrá un conjunto de indicadores adecuado. 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

Contrariamente a algunas afirmaciones aquí y en Internet, Visual Studio 2015 NO es compatible con la función __has_include , al menos según mi experiencia. Probado con la actualización 3.

Los rumores pueden haber surgido del hecho de que VS 2017 también se conoce como " Versión 15 " ;; En cambio, VS 2015 se denomina " Versión 14 " ;. El soporte para la función parece haberse introducido oficialmente con " Visual Studio 2017 Versión 15.3 " ;.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top