The Starlink build system includes support for preprocessable Fortran, in both autoconf and automake.
As described in Appendix B, the installed version
of autoconf is extended with support for preprocessable
Fortran, by adding the two macros AC_PROG_FC
and
AC_PROG_FPP
.
You should use
AC_PROG_FC
in
preference to the
macro AC_PROG_F77
described in the autoconf
manual, since the `FC' support in autoconf is more flexible
and more developed than the `F77' support, and the
older macro is likely to be deprecated in coming autoconf
releases. However a potential problem with the
AC_PROG_FC
macro is that it searches for Fortran
9x compilers before Fortran 77 ones. Fortran 9x incorporates
all of strict Fortran 77 as a subset, but no more, so
if you have used any of the common Fortran extensions (which
is sometimes unavoidable), you might find the Fortran compiler
objecting. In this case, you should use the second optional
argument to AC_PROG_FC
to specify Fortran 77 as
the required dialect:
See Appendix A.12 for full details.AC_PROG_FC([], 77)
Unlike C, there is no preprocessor defined as part of the
Fortran standard, and this is inconvenient if you wish to
use a Fortran extension if it is available, but not have the
compilation fail if it is absent. This most commonly
applies to the READONLY
keyword on the Fortran
OPEN
statement. It is possible to use the C
preprocessor, cpp, with Fortran, though not
completely reliably, since the underlying syntaxes of C and
Fortran are so different that cpp is capable of
emitting invalid Fortran in some circumstances.
Both the Sun and GNU Fortran compilers can handle cpp-style
preprocessor constructs in a Fortran file, avoiding any
separate preprocessing stage. Sun have produced a Fortran
preprocessor, fpp, which is available at
<http://www.netlib.org/fortran/>
: it's freely
available, but not open-source. And more often than not we
can in fact fall back on simple cpp, as long as we have
confined ourselves to the #include
,
#define
and #if...
constructs. If
it comes to that, such simple preprocessing could be mostly
handled with a simple Perl script.
Starlink autoconf and automake between them add support for
preprocessable Fortran. Autoconf supplies the
AC_PROG_FPP
macro
described in Appendix A.13, to investigate what compiler and
preprocessor are available, and automake works with the
results of that test to add appropriate support to the
generated Makefile.in
.
For example, you might have in your
configure.ac
file the
lines
and have in yourAC_PROG_FC AC_PROG_FPP AC_FC_OPEN_SPECIFIERS(readonly,[access='sequential',recl=1])
my_io.F
the lines
#include <config.h> SUBROUTINE MYIO(...) * blah... OPEN ( UNIT = LUCON, FILE = IFCNAM, STATUS = 'OLD', #ifdef HAVE_FC_OPEN_READONLY : READONLY, #endif #ifdef HAVE_FC_OPEN_ACCESSSEQUENTIALRECL1 : ACCESS='SEQUENTIAL',RECL=1, #endif : FORM = 'UNFORMATTED', IOSTAT = ISTAT )
The file my_io.F
is listed in the
Makefile.am
as one of the _SOURCES
of
whatever library or application it contributes to, alongside
the other Fortran files. If the compiler discovered by
the ./configure
script can support preprocessor
statements itself, then the .F
file is
treated like any other; if not, and a separate preprocessing
stage is required, then the Makefile handles this
itself.
Note that we are using .F
here as the file
extension for preprocessable Fortran: see Appendix A.13 for discussion.
In those cases where you wish the preprocessing step alone, such as
when you are generating an include file from a template, you
should name the input file with a .F
extension
also. You will need to include a preprocessing rule in the makefile.
The following idiom might be helpful:
or the following, for a suffix rule# Run a .F file through the fpp preprocessor, to produce a file with # no extension. # The following deals with case-insensitive filesystems, on which # foo.f and foo.F would be the same file. FPP_OUTPUT is # either "" (in which case the preprocessor writes to foo.f, and # the filesystem is presumably case-sensitive) or ">$@". foo: foo.F rm -f foo $(FPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(FPPFLAGS) $(CPPFLAGS) foo.F $(FPP_OUTPUT) test -f foo || mv foo.f foo
In this second example, in which we have elided the useful comment, we have declared theSUFFIXES = .F .F: rm -f $@ $(FPP) $(DEFAULT_INCLUDES) $(FPPFLAGS) $(CPPFLAGS) $< $(FPP_OUTPUT) test -f $@ || mv $(<:.F=.f) $@
.F
suffix (we wouldn't have to do
this if there were `real' .F
sources in this directory),
and are using the $<
and $@
magic
variables.In second example, we elided most of the flag variables we included
in the first one, since we probably don't need them. In case of
doubt, copy the .F.f:
rule in one of the generated
Makefile.in
files.
There is a more elaborate example of this in the
prm
component.