Can the C preprocessor be used to tell if a file e

2019-01-10 18:33发布

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?

9条回答
不美不萌又怎样
2楼-- · 2019-01-10 18:58

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
查看更多
别忘想泡老子
3楼-- · 2019-01-10 19:01

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
查看更多
闹够了就滚
4楼-- · 2019-01-10 19:02

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.

查看更多
霸刀☆藐视天下
5楼-- · 2019-01-10 19:06

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
查看更多
相关推荐>>
6楼-- · 2019-01-10 19:11

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".

查看更多
叼着烟拽天下
7楼-- · 2019-01-10 19:16

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.

查看更多
登录 后发表回答