我有一个很大的代码(阅读:成千上万的模块),有的代码共享许多项目,所有运行在不同的操作系统的不同用C++编译器。不用说,保持建立过程中可以是一个相当烦琐。

有几个地方的代码,在那里它会清洁起码基本上如果只有一个方法可以做出预处理器忽略某些 #includes 如果文件不存在在前文件夹。没有人知道一种方式来实现?

目前,我们使用 #ifdef 周围 #include 在共享文件,与第二个项目-特定的文件,该文件#定义是否 #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

其他提示

小小的更新

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

扩展加入到 C++17标准 (P0061R1).

支助编译器

  • 海湾合作委员会从5.X
  • Visual Studio从VS2015更新2(?)

例(从铛的网站):

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

来源

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

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

那么header1.h:

#define header1_is_missing

现在你可以随时写

#include <header1.h>
#ifdef header1_is_missing

   // there is no header1.h 

#endif

预处理器本身无法识别文件的存在,但您当然可以使用构建环境来执行此操作。我最熟悉make,这可以让你在makefile中做这样的事情:

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

当然,你必须在像VisualStudio这样的其他构建环境中找到类似物,但我确信它们存在。

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

#define EXISTS_FILE1_C
#define EXISTS_FILE1_H
#define EXISTS_FILE2_C

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

据我所知,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参数作为 last 这样的选项传递给此目录。

GCC cpp按顺序搜索其include目录,如果它在早期目录中找到一个头文件,它将使用它。否则,它最终会找到零长度文件,并且很高兴。

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

我必须为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

与此处和互联网上的一些声明相反,Visual Studio 2015不支持 __ has_include 功能 - 至少根据我的经验。使用Update 3进行测试。

谣言可能源于VS 2017也被称为“第15版”; VS 2015被称为“版本14”。似乎已经在“Visual Studio 2017版本15.3”中正式引入了对该功能的支持。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top