C预处理器可以用来判断文件是否存在吗? 我有一个非常大的代码库(读:数千个模块),它在许多项目上共享代码,这些代码都在不同C++操作系统的不同操作系统上运行。不用说,维护构建过程可能是一件相当繁琐的事情

C预处理器可以用来判断文件是否存在吗? 我有一个非常大的代码库(读:数千个模块),它在许多项目上共享代码,这些代码都在不同C++操作系统的不同操作系统上运行。不用说,维护构建过程可能是一件相当繁琐的事情,c++,include,c-preprocessor,C++,Include,C Preprocessor,在代码库中有几个地方,如果当前文件夹中不存在该文件,那么只要有办法使预处理器忽略某些#includes,代码库就会大量清理代码。有人知道实现这一目标的方法吗 目前,我们在共享文件中的#include周围使用#ifdef,第二个项目特定文件定义项目中是否存在#include。这很管用,但很难看。在项目中添加或删除文件时,人们经常忘记正确更新定义。我曾考虑编写一个预构建工具来保持此文件的最新状态,但如果有一种与平台无关的方法来使用预处理器实现这一点,我更愿意这样做。有什么想法吗?您可以运行一个预构建

在代码库中有几个地方,如果当前文件夹中不存在该文件,那么只要有办法使预处理器忽略某些
#includes
,代码库就会大量清理代码。有人知道实现这一目标的方法吗


目前,我们在共享文件中的
#include
周围使用
#ifdef
,第二个项目特定文件定义项目中是否存在
#include
。这很管用,但很难看。在项目中添加或删除文件时,人们经常忘记正确更新定义。我曾考虑编写一个预构建工具来保持此文件的最新状态,但如果有一种与平台无关的方法来使用预处理器实现这一点,我更愿意这样做。有什么想法吗?

您可以运行一个预构建步骤,生成一个包含“定义”列表的包含文件,该列表表示当前目录中现有文件的名称:

#define EXISTS_FILE1_C
#define EXISTS_FILE1_H
#define EXISTS_FILE2_C

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

通常,这是通过使用脚本尝试运行预处理器以尝试包含该文件来完成的。根据预处理器是否返回错误,脚本将使用适当的#define(或#unde)更新生成的.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

cat>.test.h预处理器本身无法识别文件的存在,但您当然可以使用构建环境来识别文件的存在。我对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
#ifdef HEADER1_公司
#包括
#恩迪夫

另一种可能性:在某个目录的某个地方填充您希望选择性包含的所有标题的零长度版本。将-I参数作为最后一个此类选项传递到此目录

GCC cpp按顺序搜索其包含目录,如果它在早期目录中找到头文件,它将使用它。否则,它最终会找到长度为零的文件,并感到高兴


我假设其他cpp实现也会按照指定的顺序搜索它们的include目录。

为缺少的标题创建一个特殊文件夹,并使该文件夹最后被搜索
(这是特定于compliler的-在“INCLUDES”环境变量中的最后一项,类似的)

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

标题1.h:

#define header1_is_missing
现在你可以随时写作了

#include <header1.h>
#ifdef header1_is_missing

   // there is no header1.h 

#endif
#包括
#ifdef头1_缺失
//没有校长
#恩迪夫

我不得不为Symbian操作系统做类似的事情。我就是这样做的: 假设您想检查文件“file_strange.h”是否存在,并且您想根据该文件的存在包括一些标题或指向某些库的链接。

首先创建一个小批量文件,用于检查该文件是否存在。

autoconf很好,但对于许多小项目来说,它是一个致命的弱点

----------球棒

@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
----------球拍结束

然后我创建了一个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\u-supported.h
将设置适当的标志。 您可以在cpp文件甚至mmp文件中使用此标志 例如在mmp中

#include "../inc/file_strange_supported.h"
#ifdef NEW_API_SUPPORTED
LIBRARY newapi.lib
#else
LIBRARY oldapi.lib
#endif
#include "../inc/file_strange_supported.h"
#ifdef NEW_API_SUPPORTED
CStrangeApi* api = Api::NewLC();
#else
// ..
#endif
和in.cpp

#include "../inc/file_strange_supported.h"
#ifdef NEW_API_SUPPORTED
LIBRARY newapi.lib
#else
LIBRARY oldapi.lib
#endif
#include "../inc/file_strange_supported.h"
#ifdef NEW_API_SUPPORTED
CStrangeApi* api = Api::NewLC();
#else
// ..
#endif
小更新 有些编译器可能支持
\u has\u include(头名称)

扩展已添加到()中

编译器支持
  • 叮当声
  • GCC从5.X开始
  • VS2015更新2(?)中的Visual Studio
示例(来自clang网站):
//注意两种可能的文件名字符串格式。
#如果&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
#包括“myinclude.h”
#恩迪夫
来源

与这里和互联网上的一些说法相反,Visual Studio 2015不支持
\u has\u include
功能-至少根据我的经验。使用更新3进行测试


谣言可能来自VS 2017也被称为“版本15”;VS 2015被称为“第14版”。对该功能的支持似乎已随“Visual Studio 2017 15.3版”正式推出。

这将是C++17的一部分!如果我正确地解释了,此功能将添加到C2X中。在Objective-C中很有用,可以测试iOS中是否存在其他库/组件(看着您以本机方式反应),我想这是标准“配置”unix/linux工具的结束-编译器本身提供了查询是否有特定头的机制:-D+1用于使源代码本身完全可移植,并将可移植性负担转移到编译器调用本身上(这在不同的编译器之间几乎已经是不可移植的了)。我想更准确地说,不仅仅是使源代码完全可移植,而且还可以随时编译-