Pergunta

Eu tenho uma base de código muito grande (leia -se: milhares de módulos) que possuem código compartilhado em vários projetos que são executados em diferentes sistemas operacionais com diferentes compiladores C ++. Escusado será dizer que manter o processo de construção pode ser uma tarefa bastante árdua.

Existem vários lugares na base de código em que limparia o código substancialmente se houvesse uma maneira de fazer com que o pré-processador ignorasse certos #includes Se o arquivo não existir na pasta atual. Alguém sabe uma maneira de conseguir isso?

Atualmente, usamos um #ifdef em volta do #include no arquivo compartilhado, com um segundo arquivo específico do projeto que #decide se o #include existe no projeto. Isso funciona, mas é feio. As pessoas geralmente esquecem de atualizar corretamente as definições quando adicionam ou removem arquivos do projeto. Eu pensei em escrever uma ferramenta pré-construção para manter esse arquivo atualizado, mas se houver uma maneira independente da plataforma de fazer isso com o pré-processador, prefiro fazer dessa maneira. Alguma ideia?

Foi útil?

Solução

Geralmente, isso é feito usando um script que tenta executar o pré -processador na tentativa de incluir o arquivo. Dependendo se o pré -processador retornar um erro, o script atualiza um arquivo .h gerado com um #Define apropriado (ou #Undef). Em Bash, o script pode parecer vagamente assim:

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

Uma estrutura bastante completa para trabalhar portável com verificações de portabilidade como essa (assim como milhares de outras) é AutoConf.

Outras dicas

Pequena atualização

Alguns compiladores podem apoiar __has_include ( header-name ).

A extensão foi adicionada ao C ++ 17 padrão (P0061R1).

Suporte do compilador

  • Clang
  • GCC de 5.x.
  • Visual Studio do vs2015 Atualização 2 (?)

Exemplo (do site de Clang):

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

Fontes

Crie uma pasta especial para os cabeçalhos ausentes e faça com que essa pasta seja pesquisada por último
(que é específico do complilador - o último item em "inclui" variável de ambiente, algo assim)

Então se algum cabeçalho1.h pode estar ausente, crie nessa pasta um stub

Header1.h:

#define header1_is_missing

Agora você sempre pode escrever

#include <header1.h>
#ifdef header1_is_missing

   // there is no header1.h 

#endif

O próprio pré -processador não pode identificar a existência de arquivos, mas você certamente pode usar o ambiente de construção para fazê -lo. Estou familiarizado com Make, o que permitiria que você fizesse algo assim no seu Makefile:

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

Obviamente, você teria que encontrar um análogo para isso em outros ambientes de construção como o VisualStudio, mas tenho certeza de que eles existem.

Você pode ter uma etapa de pré-construção que gera um arquivo de inclusão que contém uma lista de #Defines que representam os nomes dos arquivos existentes no diretório atual:

#define EXISTS_FILE1_C
#define EXISTS_FILE1_H
#define EXISTS_FILE2_C

Em seguida, inclua esse arquivo de dentro do seu código -fonte e, em seguida, sua fonte pode testar o EXISTS_* define para ver se existe ou não um arquivo.

Até onde eu sei, o CPP não possui uma diretiva sobre a existência de um arquivo.

Você pode conseguir isso com um pouco de ajuda do Makefile, se estiver usando a mesma marca entre plataformas. Você pode detectar a presença de um arquivo no Makefile:

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

Como menciona o @Greg Hewgill, você pode fazer com que seus #includes sejam condicionais:

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

Outra possibilidade: preencha um diretório em algum lugar com versões de comprimento zero de todos os cabeçalhos que você deseja incluir opcionalmente. Passe um argumento -i para este diretório como o último Essa opção.

O GCC CPP pesquisa seus diretórios de inclusão em ordem, se encontrar um arquivo de cabeçalho em um diretório anterior, ele o usará. Caso contrário, ele encontrará o arquivo de comprimento zero e será feliz.

Presumo que outras implementações do CPP também pesquisem seus diretórios incluídos na ordem especificada.

Eu tive que fazer algo semelhante para o sistema operacional simbiano. Foi assim que eu fiz: digamos que você queira verificar se o arquivo "file_strange.h" existe e você deseja incluir alguns cabeçalhos ou link para algumas bibliotecas, dependendo da existência desse arquivo.

Primeiro, crie um pequeno arquivo em lote para verificar a existência desse arquivo.

O Autoconf é bom, mas um pouco de matar para muitos pequenos projetos.

---------- 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

Então eu criei um arquivo 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 termina

Inclua o arquivo check.mk no seu arquivo Bld.inf, ele deve estar antes dos arquivos MMP

PRJ_MMPFILES
gnumakefile checkmedialist.mk

Agora, na hora da compilação, o arquivo file_strange_supported.h terá um conjunto de bandeira apropriado. Você pode usar este sinalizador em seus arquivos CPP ou mesmo no arquivo MMP, por exemplo, no MMP

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

e em .cpp

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

Ao contrário de algumas reivindicações aqui e na internet, o Visual Studio 2015 não suporta o __has_include Recurso - pelo menos de acordo com minha experiência. Testado com a atualização 3.

Os rumores podem ter surgido do fato de que o VS 2017 também é chamado de "versão 15"; O VS 2015 é referido como "versão 14". O suporte ao recurso parece ter sido oficialmente apresentado com "Visual Studio 2017 Versão 15.3".

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top