I am fairly new to use Fortran preprocessing statement and have a question which is probably pretty native. Can Fortran preprocessing statement be indented? I tested using Gfortran 4.8.1 on Linux (openSUSE Leap) and it turned out I it can not be indented at all.
The following code main.f90 works with gfortran -cpp main.f90 -o main:
program main
implicit none
#ifdef DEBUG
print *, "I am in debug mode"
#endif
print *, "hello world!"
end program main
But the following throws an error:
program main
implicit none
#ifdef DEBUG
print *, "I am in debug mode"
#endif
print *, "hello world!"
end program main
The error message is Error: Invalid character in name at (1).
Does this mean that we should always write the preprocessing statement from the first beginning of the line or it is just a compiler specific rule? Any help would be greatly appreciated and thanks in advance!
No, they cannot be indented because gfortran runs CPP in traditional mode which does not allow indentation. They must always start in the first column.
You could run CPP manually, but be very very careful about that.
If you use the // string concatenation operator somewhere the preprocessor would treat it as a comment. You must use the -C flag as shown by #ewcz in his/her answer which disables discarding of comments.
Some compilers supply their own FPP preprocessor which behaves differently.
you could use the C preprocessor to do the processing and then compile the processed file, i.e., assuming that your program is in main.f90, then something like:
cpp -nostdinc -C -P -w main.f90 > _main.f90
gfortran -o main _main.f90
In this connection, this question is quite useful: Indenting #defines
Related
I know how to use IF and ENDIF in Fortran, but in many codes I have from others, there is a # sign before the IF, what does that mean?
!USES:
#if ( defined X )
use Y
#endif
These are pre-compiler macros, and not Fortran statements. They do the same as regular if statements, only at compile time and with a slightly different syntax.
Note that pre-processor directives are not part of any Fortran Standard, and that they are not supported by every compiler. Generally, they are identical to C pre-processor directives, but not always.
#ifdef and #endif are preprocessor directives.
suppose you had a file:
! test.F:
program A
x=1
#ifdef NEW
x=0
#endif
write(*,*) x
end
if you compile it using a preprocessor:
ifort -DNEW test.F -o a.out
you should get x =0
otherwise if you compile without -DNEW like
ifort test.F -o a.out
in that case you get x=1. The code inside the ifdef is not compiled. Here are compile time options for gfortran.. A useful situation for example is this question.
How can I stringify a preprocessor macro with GNU gfortran? I would like to pass a macro definition to GNU gfortran which will then be used as a string in the code.
Effectively I would like to do this:
program test
implicit none
character (len=:), allocatable :: astring
astring = MYMACRO
write (*, *) astring
end program test
and then build with:
gfortran -DMYMACRO=hello test.F90
I tried creating various macro, for example:
#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)
...
astring = STRINGIFY(MYMACRO)
but this doesn't work with the gfortran preprocessor.
I also tried using a different style of macro:
#define STRINGIFY(x) "x"
...
astring = STRINGIFY(MYMACRO)
but this just creates a string containing the text 'MYMACRO'.
I then tried changing the macro definition to:
-DMYMACRO=\"hello\"
but this caused unrelated problem in the build process.
Thank you for your help
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 -
Although this is an old and answered question, I wanted to achieve macro stringification in gfortran without changing the default preprocessor or build process. I found that the preprocessor would do what I want, as long as there was no initial quotation mark on the line, therefore the desired stringification can be achieved by breaking lines with ampersands:
astring = "&
&MYMACRO"
A caveat is that this really only works with the traditional preprocessor, and for examples breaks with intel ifort compiler, which is too smart to fall for this trick. My current solution is to define separate stringification macros for gfortran as:
#ifdef __GFORTRAN__
# define STRINGIFY_START(X) "&
# define STRINGIFY_END(X) &X"
#else /* default stringification */
# define STRINGIFY_(X) #X
# define STRINGIFY_START(X) &
# define STRINGIFY_END(X) STRINGIFY_(X)
#endif
program test
implicit none
character (len=:), allocatable :: astring
astring = STRINGIFY_START(MYMACRO)
STRINGIFY_END(MYMACRO)
write (*, *) astring
end program test
It looks really ugly, but it does get the job done.
Removing the quotes around x in STRINGIFY solved the problem for me:
#define STRINGIFY(x) x ! No quotes here
program test
implicit none
character (len=:), allocatable :: astring
astring = STRINGIFY(MYMACRO)
write(*,*), astring
end program test
Compiled with
gfortran -cpp -DMYMACRO=\"hello\" test.f90
The -cpp option enables the preprocessor for all extensions.
I have a compiling Problem using "code::blocks" on Windows 7. My C-code is:
//whatever
int main(void){return 0;}
//this is blank line
The MinGW commandline is:
gcc.exe -Wall -g -ansi -c C:...\Test\main.c -o obj\Debug\main.o
If i try to compile this, I get the error:
C:\...\Test\main.c|1|error: expected identifier or '(' before '/' token
(I wanted to post a picture here, but not enough reputation ...)
There are only 3 lines of code in my source file. (The last just contains \0, but I didn't know, how to add a blank line). I use code::blocks as IDE. I used notepad++ to search for non-printable chars, but with no meaningful results. I use the MinGW compiler that is available as bundled download with code::blocks. I corrected the "toolchain executables" and the compiler worked fine until now.
It's not the first time I had this problem. I remember having it on another computer before and solved it by retyping the whole source file (which I don't want to do every time).
The way the error was provoked is just commenting and uncommenting code for a while (I tried out some things and commented previous tests away). And than, out of the blue, this error appeared.
Sorry, if my grammar is bad. English is not my mother tongue.
I appreciate any given help!
Thanks in advance,
Nils
Remove the compiler option -ansi.
ANSI C does not understand //.
From the gcc documentation:
3.4 Options Controlling C Dialect
[...]
-ansi
In C mode, this is equivalent to -std=c90. In C++ mode, it is equivalent to -std=c++98.
[...] For the C compiler, it disables recognition of C++ style ‘//’ comments [...]
In code blocks do this
Make sure that highlighted option is unchecked.(This is same as above ans. removing -ansi. option.)
Settings->compiler
For compiling c use
/* C-style comments!
*/
How can I change the value of a boolean macro when I run my program through the command line? For instance, suppose I have the following macro in my cpp file, call it MyCpp.cpp
#define DEBUG 1
How can I change this when I run my program? through the command line:
g++ -Wall -Wextra -o MyCpp MyCpp.cpp
I am pretty sure you specify some kind of command line option, does this ring any bells?
Also, I do NOT want to use argv[]
First, change your source code:
#ifndef DEBUG
# define DEBUG 1
#endif
Now you can say on the command line:
g++ -Wall -Wextra -o MyCpp MyCpp.cpp -DDEBUG=5
# ^^^^^^^^^
The command line argument -DFOO=bar has the same effect as putting #define FOO bar in your source code; you need the #ifndef guard to avoid an illegal redefinition of the macro.
Sometimes people use an auxiliary macro to prevent the definition of another macro:
#ifndef SUPPRESS_FOO
# define FOO
#endif
// ... later
#ifdef FOO
// ...
#endif
Now say -DSUPPRESS_FOO to not define FOO in the code...
How can I change the value of a boolean macro when I run my program through the command line?
As it stands, you can't. You are using a preprocessor symbol so the decision as to whether debug information should be printed is a compile time decision. You are going to have to change that compile-time DEBUG symbol to a run-time variable that you set by parsing the command line, via some configuration file read in at run time, or both.
Parsing the command line isn't that hard. There are plenty of low-level C-style tools to help you do that. Boost has a much more powerful C++ based scheme. The trick then is to change those compile-time debug decisions to run-time decisions. At the simplest, it's not that hard: Just replace that DEBUG preprocessor symbol with a global variable. You can get quite a bit more sophisticated than this of course. Eventually you'll have a configurable logging system. Boost has that, too.
Please note the following. If you have in your c/cpp file or one of your included header files:
#define DEBUG 1
then you cannot modify this definition using the command line of the compiler (makefile). There is simply no chance. The cpp file will simply overwrite the command line setting.
Is there any way for gfortran to compile a f90 program but with a non-f90 extension, or even no file extension at all?
How to suppress pause statement warning used in a f90 program when compiled with gforTRan?
Many thanks.
gfortran -c sourfile.xyz does not work. I know the manpage explains these options, but I did not find one working.
I mean in my f90 program, I have a pause statement. If I compile it, I got a warning saying the use of pause is obsolete. I want to suppress this warning during compilation.
Suppress all warnings with -w option?