Your attempt to use the well-known stringification recipe of the C preprocessor,
viz:
#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)
fails for two reasons, each sufficient by itself.
First and simplest, the source file in which you attempt to employ it apparently
has the extension .f90
. What this extension signifies to gfortran
(and to
the GCC compiler driver, by any other name) is: Free form Fortran source code that should not be preprocessed.
Similarly .f95
, .f03
and .f08
. If you want gfortran
to infer that a source
file contains free form Fortran code that must be preprocessed, give it one of
the extensions .F90
, .F95
, .F03
or .F08
. See the GCC documentation of
these points
Even if you do that simple thing, however, the second reason bites.
The use of the C preprocessor to preprocess Fortran source is as old as C
(which though old, is much younger than Fortran). gfortran
is obliged not
to break ancient working code; so, when it invokes the C preprocessor,
it invokes it in traditional mode. The traditional mode of the C preprocessor
is the way in which the preprocessor behaved prior to the first standardization
of the C language (1989), insofar as that unstandardized behaviour can be pinned down. In traditional
mode, the preprocessor does not recognize the stringizing operator '#', which was
introduced by the first C Standard. You can verify this by invoking the preprocessor
directly like:
cpp -traditional test.c
where test.c
contains some attempt to employ the stringification recipe. The
attempt fails.
You cannot coax gfortran
on its own to work the the stringification recipe.
But there is a workaround. You can invoke cpp
directly, unencumbered by traditional mode,
to preprocess the Fortran source in which you want the stringification done and relay its
output to gfortran
. If you already know this and were looking for a gfortran
-alone
solution you need read no further.
Doing the stringification in your test source this way would look like:
cpp -std=c89 '-DSTRINGIFY_(x)=#x' '-DSTRINGIFY(x)=STRINGIFY_(x)' '-DMYMACRO=STRINGIFY(hello)' test.f90
The output of that is:
# 1 "test.f90"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "test.f90"
program test
implicit none
character (len=:), allocatable :: astring
astring = "hello"
write (*, *) astring
end program test
And that output is what you want to to compile. You could accomplish that as well by:
cpp -std=c89 '-DSTRINGIFY_(x)=#x' '-DSTRINGIFY(x)=STRINGIFY_(x)' \
'-DMYMACRO=STRINGIFY(hello)' test.f90 > /tmp/test.f90 \
&& gfortran -o test /tmp/test.f90
Then you will find that ./test
exists and that executing it outputs hello
.
You can eliminate the intermediate temporary file with further refinement. Your F90 source
code will compile as F95, as the latter is conservative of the former. So you can take
advantage of the fact that GCC will compile source piped to its standard input if
you tell it what language you are piping, using its -x
language option. The
Fortran dialects that you may specify in this way are f77
, f77-cpp-input
, f95
and f95-cpp-input
, where the -cpp-input
prefix denotes that
the source is to be preprocessed and its absence denotes that it is not. Thus
cpp -std=c89 '-DSTRINGIFY_(x)=#x' '-DSTRINGIFY(x)=STRINGIFY_(x)' \
'-DMYMACRO=STRINGIFY(hello)' test.f90 | gfortran -x f95 -o test -
works as well as the previous solution, minus the temporary file, and emits
the innocuous warning:
Warning: Reading file '<stdin>' as free form
(Note and retain the final -
on the commandline. That is what tells gfortran
to
compile the standard input.). The meaning of -x f95
brings the additional
economy that the source, which is preprocessed by cpp
, is not preprocessed
again by the compiler.
The use of the option -std=c89
when invoking cpp
calls for a cautionary
explanation. It has the effect of making cpp
conform to the earliest C Standard.
That is as close to -traditional
as we can get while still availing of the
#
-operator, on which the stringification recipe depends, But with it you embrace
the possibility of breaking some Fortran code if you preprocess it this way;
otherwise gfortran
itself would not enforce -traditional
. In the case of
your test program, you could safely omit -std=c89
, allowing cpp
to conform
to the default C standard when it was built. But if you permit it or direct it
to conform to -std=c99
or later, then the standard will mandate recognition
of //
as the beginning of a one-line comment (as per C++), by which any line
of Fortran that contains the concatenation operator will be truncated at the
first occurrence.
Naturally, if you use are using make
or another build system to build the
code in which you want the stringified macros, you will have a way of telling
the build system what actions constitute compiling a given class of compilable
files. For any Fortran source file fsrc
you wanted to compile with
a stringification preamble, the actions to specify would be in the vein:
cpp -std=c89 '-DSTRINGIFY_(x)=#x' '-DSTRINGIFY(x)=STRINGIFY_(x)' \
'-DMYMACRO=STRINGIFY(hello)' fsrc.f90 | gfortran -x f95 -c -o fsrc.o -
-DMYMACRO=\"hello\"
is the right approach. Which problems did it cause? – Wanderoo#define STRINGIFY(x) "x"
. I found that it just created a string containing the text 'MYMACRO'. – Magill