C 预处理器可以用来判断文件是否存在吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/142877/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can the C preprocessor be used to tell if a file exists?
提问by Setepenre
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.
我有一个非常大的代码库(读取:数千个模块),其中包含在众多项目中共享的代码,这些项目都运行在具有不同 C++ 编译器的不同操作系统上。不用说,维护构建过程可能是一件很麻烦的事情。
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?
#includes
如果文件在当前文件夹中不存在,那么代码库中有几个地方可以大幅清理代码,前提是有一种方法可以让预处理器忽略某些文件。有谁知道实现这一目标的方法?
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?
目前,我们使用了一个#ifdef
围绕#include
在共享文件,与第二项目特定文件#define语句是否#include
存在于该项目。这有效,但它很丑陋。人们在从项目中添加或删除文件时经常忘记正确更新定义。我已经考虑编写一个预构建工具来保持这个文件是最新的,但是如果有一种独立于平台的方式来使用预处理器来做到这一点,我宁愿这样做。有任何想法吗?
采纳答案by Logan
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:
通常这是通过使用一个脚本来完成的,该脚本尝试运行预处理器以尝试包含文件。根据预处理器是否返回错误,脚本会使用适当的 #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
A pretty thorough framework for portably working with portability checks like this (as well as thousands others) is autoconf.
autoconf是一个非常全面的框架,可移植性地处理这样的可移植性检查(以及其他数千种)。
回答by Setepenre
Little Update
小更新
Some compilers might support __has_include ( header-name )
.
一些编译器可能支持__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 (?)
- 铛
- 来自 5.X 的 GCC
- Visual Studio 来自 VS2015 Update 2 (?)
Example (from clang website):
示例(来自 clang 网站):
// Note the two possible file name string formats.
#if __has_include("myinclude.h") && __has_include(<stdint.h>)
# include "myinclude.h"
#endif
Sources
来源
回答by eugensk
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)
为丢失的标题创建一个特殊的文件夹,并使该文件夹最后被搜索
(这是编译器特定的 - “INCLUDES”环境变量中的最后一项,类似的东西)
Then if some header1.h can be missing, create in that folder a stub
然后,如果某些 header1.h 可能丢失,请在该文件夹中创建一个存根
header1.h:
标题1.h:
#define header1_is_missing
Now you can always write
现在你可以随时写
#include <header1.h>
#ifdef header1_is_missing
// there is no header1.h
#endif
回答by bmdhacks
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:
预处理器本身无法识别文件的存在,但您当然可以使用构建环境来做到这一点。我最熟悉 make,它允许你在你的 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.
当然,您必须在 VisualStudio 等其他构建环境中找到类似的方法,但我确信它们存在。
回答by DGentry
So far as I know cpp does not have a directive regarding the existence of a file.
据我所知,cpp 没有关于文件存在的指令。
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:
如果您跨平台使用相同的 make,您可能能够在 Makefile 的帮助下完成此操作。您可以检测 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:
正如@Greg Hewgill 提到的,你可以让你的#includes 成为有条件的:
#ifdef HEADER1_INC
#include <header1.h>
#endif
回答by DGentry
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 lastsuch option.
另一种可能性:在某个目录中填充您希望包含的所有标头的零长度版本。将 -I 参数作为最后一个此类选项传递给此目录。
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.
GCC cpp 按顺序搜索其包含目录,如果它在较早的目录中找到头文件,它将使用它。否则,它最终会找到零长度的文件,并且很高兴。
I presume that other cpp implementations also search their include directories in the order specified.
我假设其他 cpp 实现也按指定的顺序搜索它们的包含目录。
回答by Greg Hewgill
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:
您可以运行一个预构建步骤来生成一个包含文件,该文件包含一个 #defines 列表,这些 #defines 代表当前目录中存在的文件的名称:
#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.
然后,从源代码中包含该文件,然后您的源可以测试EXISTS_*
定义以查看文件是否存在。
回答by Ahmad Mushtaq
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.
我不得不为 Symbian OS 做一些类似的事情。我就是这样做的:假设您想检查文件“file_strange.h”是否存在,并且您想根据该文件的存在情况包含一些头文件或链接到一些库。
first creat a small batch file for checking the existence of that file.
首先创建一个小的批处理文件来检查该文件的存在。
autoconf is good but an over kill for many small projects.
autoconf 很好,但对许多小项目来说是一种过度杀戮。
----------check.bat
----------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
----------check.bat 结束
then i created a gnumake file
然后我创建了一个 gnumake 文件
----------checkmedialist.mk
----------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
----------check.mk 结束
include the check.mk file in your bld.inf file, it MUST be before your MMP files
在您的 bld.inf 文件中包含 check.mk 文件,它必须在您的 MMP 文件之前
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
现在在编译时文件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
and in .cpp
并在.cpp
#include "../inc/file_strange_supported.h"
#ifdef NEW_API_SUPPORTED
CStrangeApi* api = Api::NewLC();
#else
// ..
#endif
回答by Christoph Lipka
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.
与此处和互联网上的一些声明相反,Visual Studio 2015 不支持该__has_include
功能 - 至少根据我的经验。使用更新 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".
谣言可能是因为 VS 2017 也被称为“第 15 版”;VS 2015 被称为“版本 14”。“Visual Studio 2017 版本 15.3”似乎已经正式引入了对该功能的支持。