可以使用C预处理器来判断文件是否存在吗?
我有一个非常大的代码库(阅读:数千个模块),该代码具有在多个项目上共享的代码,这些项目都在具有不同C ++编译器的不同操作系统上运行。不用说,维护构建过程可能会很麻烦。
如果只有一种方法可以使预处理器忽略某些" #includes"(如果当前文件夹中不存在该文件),那么在代码库中有很多地方可以对代码进行实质性的清理。有谁知道实现这一目标的方法?
当前,我们在共享文件中的" #include"周围使用" #ifdef",还有第二个特定于项目的文件,该文件#定义项目中是否存在" #include"。这行得通,但是很丑。人们在项目中添加或者删除文件时,常常会忘记正确更新定义。我打算编写一个预构建工具来使该文件保持最新状态,但是如果有一种与平台无关的方法可以使用预处理器来执行此操作,则我宁愿以这种方式进行操作。有任何想法吗?
解决方案
我们可以运行一个预构建步骤,以生成一个包含文件,该包含文件包含#define列表,这些列表表示当前目录中现有文件的名称:
#define EXISTS_FILE1_C #define EXISTS_FILE1_H #define EXISTS_FILE2_C
然后,从源代码中包含该文件,然后源就可以测试" EXISTS_ *"定义以查看文件是否存在。
通常,这是通过使用一个脚本来完成的,该脚本尝试运行预处理器以尝试包含该文件。根据预处理器是否返回错误,脚本将使用适当的#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是一个非常全面的框架,可移植性可用于此类的可移植性检查(以及数千种其他检查)。
预处理器本身无法识别文件的存在,但是我们当然可以使用构建环境来识别文件。我最熟悉make,它将允许我们在makefile中执行以下操作:
ifdef $(test -f filename && echo "present") DEFINE=-DFILENAME_PRESENT endif
当然,我们必须在其他构建环境(例如VisualStudio)中找到类似的东西,但是我敢肯定它们存在。
据我所知,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按顺序搜索其包含目录,如果在较早的目录中找到头文件,它将使用它。否则,它将最终找到零长度的文件并感到满意。
我假设其他cpp实现也按指定的顺序搜索其include目录。
创建一个缺少标题的特殊文件夹,并使该文件夹最后被搜索
(这是" INCLUDES"环境变量中特定于编译器的最后一项,类似这样)
然后,如果可能缺少某些header1.h,请在该文件夹中创建一个存根
header1.h:
#define header1_is_missing
现在我们可以随时写
#include <header1.h> #ifdef header1_is_missing // there is no header1.h #endif
我必须为Symbian OS做类似的事情。这是我的方法:
假设我们要检查文件" file_strange.h"是否存在,并且要根据该文件的存在性包含一些头文件或者指向某些库的链接。
首先创建一个小的批处理文件,以检查该文件是否存在。
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结束
然后我创建了一个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文件中使用此标志
例如以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