Preprocessors

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)
])