Perhaps ironically, I fall into the camp of disliking preprocessing, at
least to the extent of feeling it is a “necessary evil”, not a desirable
language feature.
Preprocessing can run the gamit from something that redefines the syntax
of the language (see RATFOR) to what Fortran provides (the INCLUDE
directive) with a lot in-between (m4, cpp, fpp, …).
The COCO preprocessor did momentarily make the cut as a standard
pre-processor, but it sounds like you might be familiar with that history
already. Looking to COCO as having been an “acceptable” preprocessor
somewhat influenzed what I added to prep(1).
To see how preprocessing can go wrong, see C (no amount of flames will
change my opinion :>).
Along those lines long ago I wrote a paper on the pros of
minimizing preprocessing and how to isolate it in wrapper routines
whenever possible. I might see if I can add that to the prep(1) or
pref(1) repository.
As a quick summary, one Fortran-ish way to minimize preprocessing is to
create programming-environment specific directores for routines, like
gfortran_mswindows/ gfortran_posix/ generic/
and then use the INCLUDE path option (usually “-I”) found on most
compilers where you have duplicate filenames in the directories and choose
one (the biggest issue here being excessive duplication of code). Some
compilers will find the first instance of the file and use it, so you
can always add -Igeneric last, but others will complain if duplicate
filenames are found.
You should always isolate code requiring extensive preprocessing in it’s
own routines in its own files as much as possible, so the body of your
code is preprocessor-free.
If there is a lot of routines involved, especially if they are re-usuable
making a separate library of the programming-environment-specific routines
is almost always a good idea.
A lot of conditional compilation can now be eliminated by using the
ISO_C_BINDING interface, as a lot of it in the past involved C interfaces
directly or indirectly (using a Fortran extension that provided the
same function as a C function).
When the conditional code still compiles on all your platforms you can
compile all the versions and use function pointers or pass procedure
names but even in those rare cases you have to be careful not to impact
performance.
I hope the stdlib project will hide preprocessing for a large amount of
users in the near future by providing things like a “POSIX” interface,
but stdlib will require some form of versioning or preprocessing for
system-related and compiler-specific issues. Even issues like support
of REAL128 kinds, and certainly an extension such as REAL256 and CUDA
features make me pretty certain the need will not be going away anytime
soon.
In the case of prep(1), better support in the Fortran standard of generic programming and
perhaps some support of plain text blocks will/could go a long way towards
reducing any need for it but in the meantime I hope it will be useful.
Fortran has multiple compiler providers, unlike a lot of recent languages.
This tends to promote the need for conditional compilation.