views:

1911

answers:

8

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?

+2  A: 

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.

Greg Hewgill
+10  A: 

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.

Logan
Should be `<<EOM` not `>>EOM`.
Joe D
+1  A: 

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.

bmdhacks
+1  A: 

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
DGentry
A: 

Hi Logan! I can't figure out how to log back in to accept your answer--I used my e-mail to login, not openid, then re-opened the question at home and now stackoverflow won't recognize me as the same user, aack--but you're absolutely right... didn't even think to look at how autoconf does it. Thanks!!!

Lisa
Lacking an openID I believe stackoverflow relies on a cookie, which is only present in the browser you used to ask the question.
DGentry
Had the same problem. http://stackoverflow.uservoice.com/pages/general/suggestions/27399
Andrew Edgecombe
+1  A: 

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.

DGentry
+6  A: 

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
eugensk00
A: 

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 END

:NEW_API
echo #define NEW_API_SUPPORTED > ../inc/file_strange_supported.h
GOTO END

:OLD_API
echo #define OLD_API_SUPPORTED > ../inc/file_strange_supported.h
GOTO END

:END

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