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.