Preprocessor
A preprocessor can be invoked before the actual compilation process to
include predefined macros and to allow conditional compilation upon these
macros. GNU Fortran passes the source code to the
GNU C Preprocessor
(CPP) in the traditional mode, if the argument -cpp
is given.
The Intel Fortran compiler includes a similar preprocessor, called
FPP,
that is enabled with command-line parameter -fpp
.
Usually, a Fortran source file with file ending in upper-case
(.F90
instead of .f90
) indicates preprocessor macros
to the compiler. The command-line flag can be omitted for such files. Other
generic and Fortran-specific preprocessors are available. See the
Fortran Wiki
for an overview.
Macros
The GNU C Preprocessor lets us generate a list of all predefined macros in the used GNU Fortran version:
$ touch empty.f90
$ gfortran13 -cpp -E -dM empty.f90
GNU Fortran 12 on FreeBSD outputs, for example:
#define __ATOMIC_ACQUIRE 2
#define __CHAR_BIT__ 8
#define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__
#define __ORDER_LITTLE_ENDIAN__ 1234
#define __ORDER_PDP_ENDIAN__ 3412
#define __GFC_REAL_10__ 1
#define __FINITE_MATH_ONLY__ 0
#define __GNUC_PATCHLEVEL__ 0
#define __GFC_INT_2__ 1
#define __SIZEOF_INT__ 4
#define __SIZEOF_POINTER__ 8
#define __GFORTRAN__ 1
#define __GFC_REAL_16__ 1
#define __STDC_HOSTED__ 0
#define __NO_MATH_ERRNO__ 1
#define __SIZEOF_FLOAT__ 4
#define _LANGUAGE_FORTRAN 1
#define __SIZEOF_LONG__ 8
#define __GFC_INT_8__ 1
#define __SIZEOF_SHORT__ 2
#define __GNUC__ 12
#define __SIZEOF_LONG_DOUBLE__ 16
#define __BIGGEST_ALIGNMENT__ 16
#define __ATOMIC_RELAXED 0
#define _LP64 1
#define __GFC_INT_1__ 1
#define __ORDER_BIG_ENDIAN__ 4321
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
#define __SIZEOF_SIZE_T__ 8
#define __SIZEOF_DOUBLE__ 8
#define __ATOMIC_CONSUME 1
#define __GNUC_MINOR__ 1
#define __GFC_INT_16__ 1
#define __LP64__ 1
#define __ATOMIC_SEQ_CST 5
#define __SIZEOF_LONG_LONG__ 8
#define __ATOMIC_ACQ_REL 4
#define __ATOMIC_RELEASE 3
#define __VERSION__ "12.1.0"
The Intel Fortran Compiler 19 on Linux includes macros similar to the following (depending on version and platform):
$ touch empty.f90
$ ifort -dryrun -E -fpp empty.f90 &>&1 | grep -e '-D' | sed 's/^\s\+-D//g' | sed 's/\\//g'
__INTEL_COMPILER=1910
__INTEL_COMPILER_UPDATE=0
__unix__
__unix
__linux__
__linux
__gnu_linux__
unix
linux
__ELF__
__x86_64
__x86_64__
__amd64
__amd64__
__INTEL_COMPILER_BUILD_DATE=20200306
__INTEL_OFFLOAD
__MMX__
__SSE__
__SSE_MATH__
__SSE2__
__SSE2_MATH__
__pentium4
__pentium4__
__tune_pentium4__
Example
The example implements preprocessor conditionals in module os
to
set the type of operating system (either Windows, macOS, Linux, or FreeBSD) at
compile time. The function os_type()
then returns an integer
indicating the current platform, using #if defined
conditionals.
! os.f90
module os
implicit none
private
integer, parameter, public :: OS_UNKNOWN = 0
integer, parameter, public :: OS_WINDOWS = 1
integer, parameter, public :: OS_MACOS = 2
integer, parameter, public :: OS_LINUX = 3
integer, parameter, public :: OS_FREEBSD = 4
public :: os_type
contains
pure function os_type()
integer :: os_type
#if defined (WIN32) || defined (_WIN32) || defined (__WIN32__) || defined (__NT__)
os_type = OS_WINDOWS
#elif defined (__APPLE__)
os_type = OS_MACOS
#elif defined (__linux__)
os_type = OS_LINUX
#elif defined (__FreeBSD__)
os_type = OS_FREEBSD
#else
os_type = OS_UNKNOWN
#endif
end function os_type
end module os
The example program example.f90
has to import the module
os
and call the function os_type()
to get the
operating system the source code was compiled on:
! example.f90
program main
use :: os
implicit none
integer :: current_os
write (*, '("Current Operating System", /, a)') repeat('-', 24)
write (*, '("Name: ")', advance='no')
current_os = os_type()
select case (current_os)
case (OS_WINDOWS)
write (*, '("Microsoft Windows (Cygwin, MSYS2)")')
case (OS_MACOS)
write (*, '("macOS")')
case (OS_LINUX)
write (*, '("GNU/Linux")')
case (OS_FREEBSD)
write (*, '("FreeBSD")')
case default
write (*, '("Unknown OS")')
end select
end program main
As CPP, the preprocessor of GNU Fortran, is not indicating the current
operating system, we have to pass the macro through argument -D
, in
this particular case, -D__FreeBSD__
:
$ gfortran13 -cpp -D__FreeBSD__ -c os.f90
$ gfortran13 -o example example.f90 os.o
$ ./example
Current Operating System
------------------------
Name: FreeBSD
Using the Intel Fortran compiler on Linux, the argument is optional, as the
macro __linux__
is predefined:
$ ifort -fpp -c os.f90
$ ifort -o example example.f90 os.o
$ ./example
Current Operating System
------------------------
Name: GNU/Linux
The compiler flag is not required for source files with endings in upper-case:
$ mv os.f90 os.F90
$ ifort -c os.F90
$ ifort -o example example.f90 os.o
References
- Fortran Wiki: Preprocessors
< Compilation | [Index] | Build Automation > |