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

发布于 2024-07-05 22:02:57 字数 450 浏览 4 评论 0 原文

我有一个非常大的代码库(即:数千个模块),其中的代码在众多项目之间共享,这些项目都运行在具有不同 C++ 编译器的不同操作系统上。 不用说,维护构建过程可能是一件很苦差事。

如果当前文件夹中不存在该文件,只要有一种方法可以让预处理器忽略某些#includes,代码库中的多个位置就会大幅清理代码。 有谁知道如何实现这一目标?

目前,我们在共享文件中的 #include 周围使用 #ifdef,并使用第二个特定于项目的文件 #defines 是否包含 #include< /code> 存在于项目中。 这可行,但很丑。 人们在从项目中添加或删除文件时经常忘记正确更新定义。 我曾考虑编写一个预构建工具来保持此文件最新,但如果有一种独立于平台的方法可以使用预处理器来执行此操作,我宁愿这样做。 有任何想法吗?

I have a very large codebase (read: thousands of modules) that has code shared across numerous projects that all run on different operating systems with different C++ compilers. Needless to say, maintaining the build process can be quite a chore.

There are several places in the codebase where it would clean up the code substantially if only there were a way to make the pre-processor ignore certain #includes if the file didn't exist in the current folder. Does anyone know a way to achieve that?

Presently, we use an #ifdef around the #include in the shared file, with a second project-specific file that #defines whether or not the #include exists in the project. This works, but it's ugly. People often forget to properly update the definitions when they add or remove files from the project. I've contemplated writing a pre-build tool to keep this file up to date, but if there's a platform-independent way to do this with the preprocessor I'd much rather do it that way instead. Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

摇划花蜜的午后 2024-07-12 22:02:58

为丢失的标头创建一个特殊文件夹,并让该文件夹最后被搜索
(这是编译器特定的 - “INCLUDES”环境变量中的最后一项,类似的东西)

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

header1.h:

#define header1_is_missing

现在您可以随时写

#include <header1.h>
#ifdef header1_is_missing

   // there is no header1.h 

#endif

Create a special folder for missing headers, and make that folder to be searched last
(that is compliler specific - last item in "INCLUDES" environment variable, something like that)

Then if some header1.h can be missing, create in that folder a stub

header1.h:

#define header1_is_missing

Now you can always write

#include <header1.h>
#ifdef header1_is_missing

   // there is no header1.h 

#endif
黯然#的苍凉 2024-07-12 22:02:58

通常,这是通过使用尝试运行预处理器以尝试包含文件的脚本来完成的。 根据预处理器是否返回错误,脚本会使用适当的#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

Generally this is done by using a script that tries running the preprocessor on an attempt at including the file. Depending on if the preprocessor returns an error, the script updates a generated .h file with an appropriate #define (or #undef). In bash, the script might look vaguely like this:

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

A pretty thorough framework for portably working with portability checks like this (as well as thousands others) is autoconf.

蓝色星空 2024-07-12 22:02:58

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

#define EXISTS_FILE1_C
#define EXISTS_FILE1_H
#define EXISTS_FILE2_C

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

You could have a pre-build step run that generates an include file that contains a list of #defines that represent the names of the files existing in the current directory:

#define EXISTS_FILE1_C
#define EXISTS_FILE1_H
#define EXISTS_FILE2_C

Then, include that file from within your source code, and then your source can test the EXISTS_* defines to see whether a file exists or not.

柳若烟 2024-07-12 22:02:58

另一种可能性:在某个目录中填充您希望包含的所有标头的零长度版本。 将 -I 参数传递给此目录作为 last 此类选项。

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

我认为其他 cpp 实现也会按指定的顺序搜索其包含目录。

Another possibility: populate a directory somewhere with zero-length versions of all of the headers you wish to optionally include. Pass a -I argument to this directory as the last such option.

The GCC cpp searches its include directories in order, if it finds a header file in an earlier directory it will use it. Otherwise, it will eventually find the zero-length file, and be happy.

I presume that other cpp implementations also search their include directories in the order specified.

月朦胧 2024-07-12 22:02:58

预处理器本身无法识别文件的存在,但您当然可以使用构建环境来执行此操作。 我最熟悉 make,它允许您在 makefile 中执行类似的操作:

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

当然,您必须在 VisualStudio 等其他构建环境中找到与此类似的内容,但我确信它们存在。

The preprocessor itself cannot identify the existence of files but you certainly can use the build environment to do so. I'm mostly familiar with make, which would allow you to do something like this in your makefile:

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

Of course, you'd have to find an analog to this in other build environments like VisualStudio, but I'm sure they exist.

想你的星星会说话 2024-07-12 22:02:58

据我所知,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

So far as I know cpp does not have a directive regarding the existence of a file.

You might be able to accomplish this with a bit of help from the Makefile, if you're using the same make across platforms. You can detect the presence of a file in the Makefile:

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

As @Greg Hewgill mentions, you can then make your #includes be conditional:

#ifdef HEADER1_INC
#include <header1.h>
#endif
遮云壑 2024-07-12 22:02:58

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

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

Contrary to some claims here and on the internet, Visual Studio 2015 does NOT support the __has_include feature - at least according to my experience. Tested with Update 3.

The rumors may have arisen from the fact that VS 2017 is also referred to as "Version 15"; VS 2015 is instead referred to as "Version 14". Support for the feature seems to have been officially introduced with "Visual Studio 2017 Version 15.3".

゛时过境迁 2024-07-12 22:02:58

我必须为 Symbian 操作系统做类似的事情。 我就是这样做的:
假设您想要检查文件“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 结束

将 check.mk 文件包含在您的 bld.inf 文件中,它必须位于 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

I had to do something similar for the Symbian OS. This is how i did it:
lets say you want to check if the file "file_strange.h" exists and you want to include some headers or link to some libraries depending on the existance of that file.

first creat a small batch file for checking the existence of that file.

autoconf is good but an over kill for many small projects.

----------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 ends

then i created a gnumake file

----------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 ends

include the check.mk file in your bld.inf file, it MUST be before your MMP files

PRJ_MMPFILES
gnumakefile checkmedialist.mk

now at compile time the file file_strange_supported.h will have an appropriate flag set.
you can use this flag in your cpp files or even in the mmp file
for example in mmp

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

and in .cpp

#include "../inc/file_strange_supported.h"
#ifdef NEW_API_SUPPORTED
CStrangeApi* api = Api::NewLC();
#else
// ..
#endif
假情假意假温柔 2024-07-12 22:02:57

一些更新

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

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

来自 VS2015 Update 2 的 5.X Visual Studio 的编译器支持

  • Clang
  • GCC
  • (?)

示例(来自 clang 网站):

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

来源

Little Update

Some compilers might support __has_include ( header-name ).

The extension was added to the C++17 standard (P0061R1).

Compiler Support

  • Clang
  • GCC from 5.X
  • Visual Studio from VS2015 Update 2 (?)

Example (from clang website):

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

Sources

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文