Pergunta

How do I find out at “compile time” (e.g. using the preprocessor) if the compiler supports a particular language feature? The concrete example I am thinking of is the NEWUNIT specifier of Fortran 2008. I would like to do something like this:

#ifdef HAVE_NEWUNIT
! go ahead and use that
#else
! activate workaround
#endif

I am tagging this question fortran because that is what I am concerned with at the moment, though I suspect a general answer may have to go beyond Fortran (autoconf??). Of course, the solution should work with as many compilers as possible, but mostly, I care about gfortran and ifort (both of which have introduced NEWUNIT semi-recently).

Clarification:

  1. I am looking for an automatic way to handle such a situation. (Which might include more than just a Fortran source file -- Makefiles …)
  2. I do not care very much if it is “standard” as long as it would work on most Unix-type systems.
Foi útil?

Solução

If you are going to go down the route of using autotools, specifically autoconf the following would be how I'd code it all up.

Create the configure.ac:

dnl                                               -*- Autoconf -*-
dnl Process this file with autoconf to produce a configure script.
dnl

AC_PREREQ(2.61)
AC_INIT([test], [0.0.1], [me@example.com])

# Define our M4 macro directory
AC_CONFIG_MACRO_DIR([m4])

# Put our generated config header in the source directory
AC_CONFIG_HEADERS([src/config.h])

# Make sure we have a fortran compiler
AC_PROG_FC([ifort xlf pgfortran gfortran])
AC_LANG([Fortran])
AC_FC_FREEFORM

# Check for newunit option to open()
AX_F08_NEWUNIT

AC_OUTPUT

Create the ax_f08_newunit.m4 macro in the m4/ sub-directory. Since this is where I specified the macros are in configure.ac:

AC_DEFUN([AX_F08_NEWUNIT], [

AC_REQUIRE([AC_PROG_FC])
AC_LANG_PUSH([Fortran])

AC_MSG_CHECKING([for NEWUNIT support])
AC_COMPILE_IFELSE([
       program conftest
       integer :: i
       open(newunit=i,file='test')
       end program conftest],
[ax_f08_newunit=yes], [ax_f08_newunit=no])

AC_LANG_POP([Fortran])

if test "x$ax_f08_newunit" = "xyes"; then
    AC_MSG_RESULT([yes])
    AC_DEFINE([HAVE_NEWUNIT], [1], [NEWUNIT support])
else
    AC_MSG_RESULT([no])
fi

])

Then follow all the usual autotools routines:

aclocal -I m4
autoheader
autoconf

Then you can run ./configure, this is my output:

checking for Fortran compiler default output file name... a.out
checking whether the Fortran compiler works... yes
checking whether we are cross compiling... no
checking for suffix of executables...
checking for suffix of object files... o
checking whether we are using the GNU Fortran compiler... no
checking whether ifort accepts -g... yes
checking for Fortran flag needed to allow free-form source... -FR
checking for NEWUNIT support... yes
configure: creating ./config.status
config.status: creating src/config.h

Finally in your src/config.h file you should have:

/* src/config.h.  Generated from config.h.in by configure.  */
/* src/config.h.in.  Generated from configure.ac by autoheader.  */

/* NEWUNIT support */
#define HAVE_NEWUNIT 1

/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "me@example.com"

/* Define to the full name of this package. */
#define PACKAGE_NAME "test"

/* Define to the full name and version of this package. */
#define PACKAGE_STRING "test 0.0.1"

/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "test"

/* Define to the version of this package. */
#define PACKAGE_VERSION "0.0.1"

Of course your source code has to be run through a preprocessor now too. For example src/test.F90:

program test
#include "config.h"

integer :: i

#ifdef HAVE_NEWUNIT
  open(newunit=i,file='data')
#else
  i = 7
  open(unit=i,file='data')
#endif

end program test

When compiling the test program ifort understands that the capital F means the file needs to be preprocessed.

Outras dicas

(Standard) Fortran doesn't really have the facility to do what you want. Most (?) of us (Fortran programmers) would test the availability of a new feature by compiling a code which used it and studying the compiler messages. We might, also, consult compiler documentation.

Fortran preprocessors, which are not defined by the Fortran standard, are, in my experience, usually C preprocessors which have been taught enough about Fortran to be almost usable; think of teaching a dog to walk on two legs, it's never going to be truly bipedal and it's perfectly good at quadripedal locomotion so what's the point ?

Leaving my own prejudices aside for a moment, there is no standard way to check, at compile-time, the availability of a new feature other than by trying to compile a code which uses it.

There was a Technical Report on Conditional Compilation for Fortran back in the 90s (I think) but the extensions to the language it proposed have not found their way into more recent editions of Fortran.

In response to OP's clarification:

One approach would be to follow the lead of a lot of Linux software and to use tools such as automake and autoconf to first determine the capabilities of the (in this case) Fortran compiler, and later to either write (perhaps using a macro-processor) or to select the necessary fragments of code and thereby to construct a compilable program. In other words, configure, make and install.

Since it is far from trivial to determine at compile time what unit numbers might be in use when a new one is needed at run time I suppose you'd have to fall back on the old-fashioned approach of selecting new unit numbers from a pre-defined range which you know (or, if the code is sufficiently large and complex, just hope) is not already in use.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top