Stringify macro with GNU gfortran - fortran
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.
Related
What kind of code is in that file *.cpp.. #define mdTyVzgFy4_0UFy9GimmM
I just downloaded an open source code from a library called aruco for QR code detection written in C++, and while I was examing the code I found some files that doesn't look like c++.. Would anyone understand what kind of code is that? It looks like that #define mUXyv8dbk5ppT_acPhWw1 mFzTZaNOrvPJ32i9gU3Wr9J28M8DBzQ(a,:,[,+,c,+,:,^,Z,Z,/,-,r,O,[,;,9,e,;,P) #define mmdgJNaGE2dbCM6TccQ56 mkzSZJDew824aa0gKauM6fZ2VRvPUyZ(^,Q,5,r,j,P,t,B,c,;,T,A,o,W,},u,*,e,7,/) #define mVBw_rTkATYMOTRmsNe_B mGJoExPsp9LQpgvTNdOhH4AqaFjFPrq(+,W,4,t,i,o,d,2,e,P,1,A,:,a,E,S,v,F,Y,V) #define mH9xkXr1In9WhMDYLLAkQ mhN2hPhnFFq5alNSwVOjtfx8xECWu2g(R,r,R,z,t,2,i,b,!,k,S,n,e,C,k,K,5,o,K,a) #define mSye5PefiM2uFq__QqZRQ m_dk3EP_dRaChCeAYkjUT4mGB6eHLjG(s,Y,^,r,*,P,D,X,y,^,b,},k,4,a,=,i,X,!,v) #define mJpQJFURUc57_1UwCTPvr mByXC_NAGVGzCcmUEv_c9mAYK8t5jBN(t,R,.,>,!,i,W,0,R,C,*,Y,A,>,K,h,T,-,*,8) #define my9E4sAt6II28meWefBqO mu1aRcYPGwwmkdvLrXjWyYkshrNbQfZ(8,N,+,t,},r,I,T,=,C,*,h,!,m,{,/,D,y,_,T) #define mRtPBvwiZzHWglctKPmaF msiqIfe8Aci2FIHOTIR3qsdKyqc9jUO(7,i,j,^,_,^,6,},I,<,E,-,/,d,j,=,:,N,+,s) #endif #ifndef _ARUCO_MarkerDetector_Impl_H #define _ARUCO_MarkerDetector_Impl_H #include "aruco_export.h" #include "markerdetector.h" #include <opencv2/imgproc/imgproc.hpp> mH83V9yQZ4TlJHtn2Baef aruco mBduW7dqSuFrUAvwh7kHo mTj14DRd7xgEPvsp5xhPs CameraParameters mVlbuMLWi_vwpED0hDKIw mrJuVHPe96ExiggCdsmDG MarkerLabeler mv0LWHXRSvGJF76ckeLfO mPXYuzTL9RZjjZA9XYUV9 MarkerDetector_Impl mYwjl00gOK3Vja3UkLMIP friend mukY8albO2VdJSsWPXwW4 MarkerDetector mD07x3flmZMPVC6kwqG6P public: MarkerDetector_Impl mnODdIJiXbJxgUNOnnK7Q mYCDBBfn03HaGvoHBxAMq MarkerDetector_Impl mK8B3zN6mQAB0xYXFlxGO int dict_type, mYJJZNT6RsQUQcGvcjw6s error_correction_rate mRUhvrauugCIk8ZFUtFF5 0 mswZzmsb_awITT3YY34kR
What kind of code is in that file *.cpp.. #define mdTyVzgFy4_0UFy9GimmM #define mdTyVzgFy4_0UFy9GimmM is a pre-processor directive that defines a macro. Macros are used to replace text during pre-processing. Would anyone understand what kind of code is that? Probably no human can understand it. And that is probably the reason why that has been done in the first place: It seems to be an attempt to obfuscate the source code. You can use a pre-processor to generate the processed code to see what the compiler sees. For example, gcc -E. Note that the pre-processor will expand the include directives, so you'll need to scroll past the included files first.
Would anyone understand what kind of code is that? Yes! Wow this is fun. That is indeed an obfuscated source code. It is still C/C++. It is using pre-processor definitions. Basically it is a key that can be used multiple times. (like a variable). The compiler will search for all preprocessor definitions and replaces them by the actual text. I guess you want to deobfuscate it to have a closer look in the source code. For gcc and clang, you can use the -E option (see similar answer) to output the preprocessor output without compiling. To also show comments like in your sample output, you can add in the -CC and -P flags: clang++ -E -CC -P fileA.cpp All of the processor options for -E can be found on here, on gcc.gnu.org. -CC Do not discard comments, including during macro expansion. This is like -C, except that comments contained within macros are also passed through to the output file where the macro is expanded. -P Inhibit generation of linemarkers in the output from the preprocessor. This might be useful when running the preprocessor on something that is not C code, and will be sent to a program which might be confused by the linemarkers. For the Visual C++ compiler, you can use /E.
What does # before IF and ENDIF mean
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.
Can CPP preprocessing statement in Fortran be indented?
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
Probing language features
How do I find out at “compile time” (e.g. using the preprocessor) if the compiler supports a particular language feature? The concrete example I am thinking of is the NEWUNIT specifier of Fortran 2008. I would like to do something like this: #ifdef HAVE_NEWUNIT ! go ahead and use that #else ! activate workaround #endif I am tagging this question fortran because that is what I am concerned with at the moment, though I suspect a general answer may have to go beyond Fortran (autoconf??). Of course, the solution should work with as many compilers as possible, but mostly, I care about gfortran and ifort (both of which have introduced NEWUNIT semi-recently). Clarification: I am looking for an automatic way to handle such a situation. (Which might include more than just a Fortran source file -- Makefiles …) I do not care very much if it is “standard” as long as it would work on most Unix-type systems.
If you are going to go down the route of using autotools, specifically autoconf the following would be how I'd code it all up. Create the configure.ac: dnl -*- Autoconf -*- dnl Process this file with autoconf to produce a configure script. dnl AC_PREREQ(2.61) AC_INIT([test], [0.0.1], [me#example.com]) # Define our M4 macro directory AC_CONFIG_MACRO_DIR([m4]) # Put our generated config header in the source directory AC_CONFIG_HEADERS([src/config.h]) # Make sure we have a fortran compiler AC_PROG_FC([ifort xlf pgfortran gfortran]) AC_LANG([Fortran]) AC_FC_FREEFORM # Check for newunit option to open() AX_F08_NEWUNIT AC_OUTPUT Create the ax_f08_newunit.m4 macro in the m4/ sub-directory. Since this is where I specified the macros are in configure.ac: AC_DEFUN([AX_F08_NEWUNIT], [ AC_REQUIRE([AC_PROG_FC]) AC_LANG_PUSH([Fortran]) AC_MSG_CHECKING([for NEWUNIT support]) AC_COMPILE_IFELSE([ program conftest integer :: i open(newunit=i,file='test') end program conftest], [ax_f08_newunit=yes], [ax_f08_newunit=no]) AC_LANG_POP([Fortran]) if test "x$ax_f08_newunit" = "xyes"; then AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_NEWUNIT], [1], [NEWUNIT support]) else AC_MSG_RESULT([no]) fi ]) Then follow all the usual autotools routines: aclocal -I m4 autoheader autoconf Then you can run ./configure, this is my output: checking for Fortran compiler default output file name... a.out checking whether the Fortran compiler works... yes checking whether we are cross compiling... no checking for suffix of executables... checking for suffix of object files... o checking whether we are using the GNU Fortran compiler... no checking whether ifort accepts -g... yes checking for Fortran flag needed to allow free-form source... -FR checking for NEWUNIT support... yes configure: creating ./config.status config.status: creating src/config.h Finally in your src/config.h file you should have: /* src/config.h. Generated from config.h.in by configure. */ /* src/config.h.in. Generated from configure.ac by autoheader. */ /* NEWUNIT support */ #define HAVE_NEWUNIT 1 /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "me#example.com" /* Define to the full name of this package. */ #define PACKAGE_NAME "test" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "test 0.0.1" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "test" /* Define to the version of this package. */ #define PACKAGE_VERSION "0.0.1" Of course your source code has to be run through a preprocessor now too. For example src/test.F90: program test #include "config.h" integer :: i #ifdef HAVE_NEWUNIT open(newunit=i,file='data') #else i = 7 open(unit=i,file='data') #endif end program test When compiling the test program ifort understands that the capital F means the file needs to be preprocessed.
(Standard) Fortran doesn't really have the facility to do what you want. Most (?) of us (Fortran programmers) would test the availability of a new feature by compiling a code which used it and studying the compiler messages. We might, also, consult compiler documentation. Fortran preprocessors, which are not defined by the Fortran standard, are, in my experience, usually C preprocessors which have been taught enough about Fortran to be almost usable; think of teaching a dog to walk on two legs, it's never going to be truly bipedal and it's perfectly good at quadripedal locomotion so what's the point ? Leaving my own prejudices aside for a moment, there is no standard way to check, at compile-time, the availability of a new feature other than by trying to compile a code which uses it. There was a Technical Report on Conditional Compilation for Fortran back in the 90s (I think) but the extensions to the language it proposed have not found their way into more recent editions of Fortran. In response to OP's clarification: One approach would be to follow the lead of a lot of Linux software and to use tools such as automake and autoconf to first determine the capabilities of the (in this case) Fortran compiler, and later to either write (perhaps using a macro-processor) or to select the necessary fragments of code and thereby to construct a compilable program. In other words, configure, make and install. Since it is far from trivial to determine at compile time what unit numbers might be in use when a new one is needed at run time I suppose you'd have to fall back on the old-fashioned approach of selecting new unit numbers from a pre-defined range which you know (or, if the code is sufficiently large and complex, just hope) is not already in use.
C++ command line debug argument
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.