Preprocessors

From OctopusWiki
Jump to: navigation, search

Octopus uses the C preprocessor for Fortran code, as controlled by the FCCPP variable for the configure script. Linux systems generally have cpp installed at /lib/cpp, which is usually the one provided by GCC, and this is the default that will be used by configure. This one will work for Octopus, as will using directly GNU's cpp, or through the C compiler with gcc -E. (However, the default cpp on Mac OS will not work; use clang -E -ansi instead.) Generally -ansi should be given as an argument, which will avoid deletion of // "comments" but which are actually string concatenation in Fortran (do not use the -C flag). C compilers in general will do C preprocessing only, if passed the -E flag. The configure script will automatically decide whether the -P flag is required, avoiding insertion of line numbers in the output: generally, only g95 objects to these lines and requires the flag. In some cases, files will be parsed differently according to the suffix; in this case, you may need to add the -x c flag to cpp to tell it to treat the file as C. Another problem to watch out for is some cpp versions might remove whitespace and thus illegally combine what were supposed to be separate Fortran lines.

A basic requirement for a cpp in Fortran is:

The file below, when named conftest.f90, and preprocessed as $FCCPP conftest.f90, will contain hi and rout // ine (no space between //).

 #define ADD_I(x) x ## i
 ADD_I(h)
 #define PUSH_SUB(x) x // ine
 PUSH_SUB(rout)

For example, with cpp -ansi conftest.F90, I get:

 # 1 "conftest.F90"
 # 1 "<built-in>"
 # 1 "<command-line>"
 # 1 "conftest.F90"
 
 hi
 
 rout // ine


We try to find an acceptable preprocessor in the configure script with the following m4 macro (from m4/fortran.m4), which is licensed under GPL 2+, and also used in libxc and APE.

AC_DEFUN([ACX_FCCPP],[
     # "gcc -E -x c" means treat the file as if it were C. For some reason, when gcc identifies the source
     # as Fortran, it will not concatenate tokens in preprocessing, so we must trick it.
     for FCCPP_base in "$FCCPP" "/lib/cpp" "$CPP" "$CPP -x c" "`which cpp`"; do
         # cycle if blank
         if test -z "$FCCPP_base"; then
           continue
         fi

         for FCCPP in "$FCCPP_base" "$FCCPP_base -ansi"; do
           AC_MSG_CHECKING([whether $FCCPP is usable for Fortran preprocessing])
	   acx_fpp_ok=yes

      	   ACX_GREP_FCCPP([anything], AC_LANG_PROGRAM([],[anything]),
	     [], [acx_fpp_ok=no; AC_MSG_RESULT([preprocessor cannot be run]); break])
	     # very unlikely that adding -ansi will allow it to be run at all

      	   ACX_GREP_FCCPP([hi], AC_LANG_PROGRAM([],[
#define ADD_I(x) x ## i
ADD_I(h)]),
	     [], [acx_fpp_ok=no; AC_MSG_RESULT([preprocessor does not concatenate tokens])])

           # in Fortran this is string concatenation, must not be stripped
	   # some cpp's (e.g. icc -E -ansi) might actually insert a space between // too which is not acceptable
           ACX_GREP_FCCPP([rout // ine], AC_LANG_PROGRAM([],[
#define PUSH_SUB(x) x // ine
PUSH_SUB(rout)]),
	     [], [acx_fpp_ok=no; AC_MSG_RESULT([preprocessor mangles C++ style comment])])

	  if test x"$acx_fpp_ok" = xyes; then
            AC_MSG_RESULT([yes])
	    break
	  fi
       done
       if test x"$acx_fpp_ok" = xyes; then
	  break
       fi
     done

     if test x"$acx_fpp_ok" = xno; then
     	AC_MSG_ERROR([Could not find preprocessor usable for Fortran.])
     fi

     AC_SUBST(FCCPP)
])