Can the C preprocessor be used to tell if a file exists?
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
- SD-6: SG10 Feature Test Recommendations
- Clang Language Extensions
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
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.
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.
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.