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