C预处理器可以用来判断一个文件是否存在?

我有一个非常大的代码库(阅读:成千上万的模块),这些代码在众多的项目中共享代码,这些代码可以在不同的操作系统上运行,使用不同的C ++编译器。 不用说,维护构build过程可能相当麻烦。

如果文件不存在于当前文件夹中,只有有一种方法可以使预处理器忽略某些#includes那么在代码库中有几个地方会清除代码。 有没有人知道一个方法来实现呢?

目前,我们在共享文件的#include周围使用了一个#ifdef ,第二个项目特定的文件#define是否在项目中存在#include 。 这工作,但它是丑陋的。 人们经常忘记在项目中添加或删除文件时正确更新定义。 我已经打算编写一个预编译工具来保持这个文件是最新的,但是如果有一个独立于平台的方式来处理预处理器,我宁愿这样做。 有任何想法吗?

一般来说,这是通过使用脚本尝试运行预处理器来尝试包含文件来完成的。 根据预处理程序是否返回错误,脚本会使用适当的#define(或#undef)更新生成的.h文件。 在bash中,脚本可能看起来像这样:

 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 

一个非常透彻的框架,便携式的工作与这样的可移植性检查(以及成千上万)是autoconf 。

为缺less标题创build一个特殊文件夹,并使该文件夹最后被search
(这是compliler特定的最后一项在“INCLUDES”环境variables,类似的东西)

然后,如果某个header1.h可能会丢失,请在该文件夹中创build一个存根

那么header1.h:

 #define header1_is_missing 

现在你可以随时写

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

小更新

有些编译器可能支持__has_include ( header-name )

该扩展被添加到C ++ 17标准 ( P0061R1 )。

编译器支持

  • 来自5.X的GCC
  • VS2015更新2(?)的Visual Studio

示例(来自ng网站):

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

来源

  • SD-6:SG10functiontestingbuild议
  • 俚语语言扩展

预处理程序本身不能识别文件的存在,但是您肯定可以使用构build环境来执行此操作。 我大多熟悉make,这会让你在makefile中做这样的事情:

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

当然,在Visual Studio等其他的构build环境中,你必须find一个类似的方法,但我相信它们是存在的。

您可以进行预生成步骤运行,生成包含文件的包含文件,该文件包含表示当前目录中存在的文件名称的#define列表:

 #define EXISTS_FILE1_C #define EXISTS_FILE1_H #define EXISTS_FILE2_C 

然后,从源代码中包含该文件,然后源可以testingEXISTS_*定义以查看文件是否存在。

据我所知,cpp没有关于文件存在的指令。

如果你在平台上使用相同的make,你可以用Makefile的一些帮助来完成。 您可以在Makefile中检测到文件的存在:

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

正如@Greg Hewgill所提到的那样,你可以让你的#includes成为有条件的:

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

另一种可能性是:在一个目录中填入你想要包含的所有头文件的零长度版本。 作为最后一个这样的选项,传递一个-I参数给这个目录。

GCC cpp按顺序search它的包含目录,如果它在一个较早的目录中find一个头文件,它将使用它。 否则,最终会find零长度的文件,并开心。

我认为其他cpp实现也按指定的顺序search它们的包含目录。

我必须为Symbian OS做类似的事情。 这就是我做的:让我们说你想检查文件“file_strange.h”是否存在,你想包括一些头或链接到一些库取决于该文件的存在。

首先创build一个小batch file来检查文件的存在。

autoconf很好,但是对于很多小项目来说都是过度杀手。

———- 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结束

然后我创build了一个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结束

在你的bld.inf文件中包含check.mk文件,它必须在你的MMP文件之前

 PRJ_MMPFILES gnumakefile checkmedialist.mk 

现在在编译时file_strange_supported.h文件将有一个适当的标志集。 你可以在你的cpp文件中使用这个标志,甚至可以在mmp文件中使用这个标志

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

和.cpp

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